Skip to content

Commit

Permalink
Added elipsis in traceback fn and test cases for that
Browse files Browse the repository at this point in the history
  • Loading branch information
singul4ri7y committed Jun 14, 2024
1 parent abe7211 commit 2b70297
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 14 deletions.
12 changes: 12 additions & 0 deletions spec/traceback/anon_lua/anon_lua.pln
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- Copyright (c) 2024, The Pallene Developers
-- Pallene is licensed under the MIT license.
-- Please refer to the LICENSE and AUTHORS files for details
-- SPDX-License-Identifier: MIT

local mod: module = {}

function mod.call_anon_lua_fn(callback: () -> ())
callback()
end

return mod
15 changes: 15 additions & 0 deletions spec/traceback/anon_lua/main.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- Copyright (c) 2024, The Pallene Developers
-- Pallene is licensed under the MIT license.
-- Please refer to the LICENSE and AUTHORS files for details
-- SPDX-License-Identifier: MIT

local anon = require "spec.traceback.anon_lua.anon_lua"

local function wrapper()
anon.call_anon_lua_fn(function()
error "Error from an anonymous Lua fn!"
end)
end

-- luacheck: globals pallene_tracer_debug_traceback
xpcall(wrapper, pallene_tracer_debug_traceback)
2 changes: 1 addition & 1 deletion spec/traceback/depth_recursion/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
-- Please refer to the LICENSE and AUTHORS files for details
-- SPDX-License-Identifier: MIT

local pallene = require 'spec.traceback.depth_recursion.depth_recursion'
local pallene = require "spec.traceback.depth_recursion.depth_recursion"

-- luacheck: globals lua_fn
function lua_fn(depth)
Expand Down
4 changes: 2 additions & 2 deletions spec/traceback/module_lua/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
-- Please refer to the LICENSE and AUTHORS files for details
-- SPDX-License-Identifier: MIT

local another_module = require 'spec.traceback.module_lua.another_module'
local pallene = require 'spec.traceback.module_lua.module_lua'
local another_module = require "spec.traceback.module_lua.another_module"
local pallene = require "spec.traceback.module_lua.module_lua"

-- luacheck: globals lua_1
function lua_1()
Expand Down
6 changes: 3 additions & 3 deletions spec/traceback/module_pallene/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
-- Please refer to the LICENSE and AUTHORS files for details
-- SPDX-License-Identifier: MIT

local pallene = require 'spec.traceback.module_pallene.module_pallene'
local pallene_alt = require 'spec.traceback.module_pallene.module_pallene_alt'
local pallene = require "spec.traceback.module_pallene.module_pallene"
local pallene_alt = require "spec.traceback.module_pallene.module_pallene_alt"

-- luacheck: globals lua_2
function lua_2()
error "There's an error in everyday life. Shame!"
error "There's an error in everyday life. Alas!"
end

-- luacheck: globals lua_1
Expand Down
2 changes: 1 addition & 1 deletion spec/traceback/rect/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
-- Please refer to the LICENSE and AUTHORS files for details
-- SPDX-License-Identifier: MIT

local rect = require 'spec.traceback.rect.rect'
local rect = require "spec.traceback.rect.rect"

-- Should be local.
-- Making it global so that it is visible in the traceback.
Expand Down
19 changes: 19 additions & 0 deletions spec/traceback/stack_overflow/main.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-- Copyright (c) 2024, The Pallene Developers
-- Pallene is licensed under the MIT license.
-- Please refer to the LICENSE and AUTHORS files for details
-- SPDX-License-Identifier: MIT

local so = require "spec.traceback.stack_overflow.stack_overflow"

-- luacheck: globals please_dont_overflow
function please_dont_overflow()
so.no_overflow(please_dont_overflow)
end

-- luacheck: globals wrapper
function wrapper()
please_dont_overflow()
end

-- luacheck: globals pallene_tracer_debug_traceback
xpcall(wrapper, pallene_tracer_debug_traceback)
12 changes: 12 additions & 0 deletions spec/traceback/stack_overflow/stack_overflow.pln
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- Copyright (c) 2024, The Pallene Developers
-- Pallene is licensed under the MIT license.
-- Please refer to the LICENSE and AUTHORS files for details
-- SPDX-License-Identifier: MIT

local mod: module = {}

function mod.no_overflow(callback: () -> ())
callback()
end

return mod
45 changes: 44 additions & 1 deletion spec/traceback_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ end)

it("Multi-module Pallene", function()
assert_test("module_pallene", [[
Runtime error: spec/traceback/module_pallene/main.lua:11: There's an error in everyday life. Shame!
Runtime error: spec/traceback/module_pallene/main.lua:11: There's an error in everyday life. Alas!
Stack traceback:
C: in function 'error'
spec/traceback/module_pallene/main.lua:11: in function 'lua_2'
Expand Down Expand Up @@ -94,3 +94,46 @@ Stack traceback:
]])
end)

it("Stack overflow", function()
assert_test("stack_overflow", [[
Runtime error: C stack overflow
Stack traceback:
spec/traceback/stack_overflow/stack_overflow.pln:8: in function 'no_overflow'
spec/traceback/stack_overflow/main.lua:10: in function 'please_dont_overflow'
spec/traceback/stack_overflow/stack_overflow.pln:8: in function 'no_overflow'
spec/traceback/stack_overflow/main.lua:10: in function 'please_dont_overflow'
spec/traceback/stack_overflow/stack_overflow.pln:8: in function 'no_overflow'
spec/traceback/stack_overflow/main.lua:10: in function 'please_dont_overflow'
spec/traceback/stack_overflow/stack_overflow.pln:8: in function 'no_overflow'
spec/traceback/stack_overflow/main.lua:10: in function 'please_dont_overflow'
spec/traceback/stack_overflow/stack_overflow.pln:8: in function 'no_overflow'
spec/traceback/stack_overflow/main.lua:10: in function 'please_dont_overflow'
... (Skipped 379 frames) ...
spec/traceback/stack_overflow/stack_overflow.pln:8: in function 'no_overflow'
spec/traceback/stack_overflow/main.lua:10: in function 'please_dont_overflow'
spec/traceback/stack_overflow/stack_overflow.pln:8: in function 'no_overflow'
spec/traceback/stack_overflow/main.lua:10: in function 'please_dont_overflow'
spec/traceback/stack_overflow/stack_overflow.pln:8: in function 'no_overflow'
spec/traceback/stack_overflow/main.lua:10: in function 'please_dont_overflow'
spec/traceback/stack_overflow/main.lua:15: in function 'wrapper'
C: in function 'xpcall'
spec/traceback/stack_overflow/main.lua:19: in <main>
C: in function '<?>'
]])
end)

it("Anonymous lua functions", function()
assert_test("anon_lua", [[
Runtime error: spec/traceback/anon_lua/main.lua:10: Error from an anonymous Lua fn!
Stack traceback:
C: in function 'error'
spec/traceback/anon_lua/main.lua:10: in function '<?>'
spec/traceback/anon_lua/anon_lua.pln:8: in function 'call_anon_lua_fn'
spec/traceback/anon_lua/main.lua:9: in function '<?>'
C: in function 'xpcall'
spec/traceback/anon_lua/main.lua:15: in <main>
C: in function '<?>'
]])
end)
96 changes: 90 additions & 6 deletions src/pallene/pallenelib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ return [==[
/* Pallene stack reference entry for the registry. */
#define PALLENE_TRACER_STACK_ENTRY "__PALLENE_TRACER_STACK"
/* Traceback elipsis threshold. */
#define PALLENE_TRACEBACK_TOP_THRESHOLD 10
/* This should always be 2 fewer than top threshold, for symmetry.
Becuase we will always have 2 tail frames lingering around at
at the end which is not captured by '_countlevels'. */
#define PALLENE_TRACEBACK_BOTTOM_THRESHOLD 8
/* PALLENE TRACER RELATED DATA-STRUCTURES. */
/* Whether the frame is a Pallene->Pallene or Lua->Pallene call. */
Expand Down Expand Up @@ -237,6 +244,58 @@ static bool _pgf_name(lua_State *L) {
return false;
}
/* Returns the maximum number of levels in Lua stack. */
static int _countlevels (lua_State *L) {
lua_Debug ar;
int li = 1, le = 1;
/* Find an upper bound */
while (lua_getstack(L, le, &ar)) {
li = le, le *= 2;
}
/* Do a binary search */
while (li < le) {
int m = (li + le)/2;
if (lua_getstack(L, m, &ar)) li = m + 1;
else le = m;
}
return le - 1;
}
/* Counts the number of white and black frames in the Pallene call stack. */
static void _countframes(pt_frame_t *frame, int *mwhite, int *mblack) {
*mwhite = *mblack = 0;
while(frame != NULL) {
*mwhite += (frame->type == PALLENE_TRACER_FRAME_TYPE_C);
*mblack += (frame->type == PALLENE_TRACER_FRAME_TYPE_LUA);
frame = frame->prev;
}
}
/* Responsible for printing and controlling some of the traceback fn parameters. */
static void _dbg_print(const char *buf, bool *elipsis, int *pframes, int nframes) {
/* We have printed the frame, even tho it might not be visible ;). */
(*pframes)++;
/* Should we print? Are we in the point in top or bottom printing threshold? */
bool should_print = (*pframes <= PALLENE_TRACEBACK_TOP_THRESHOLD)
|| ((nframes - *pframes) <= PALLENE_TRACEBACK_BOTTOM_THRESHOLD);
if(should_print)
fprintf(stderr, buf);
else if(*elipsis) {
fprintf(stderr, "\n ... (Skipped %d frames) ...\n\n",
nframes - (PALLENE_TRACEBACK_TOP_THRESHOLD
+ PALLENE_TRACEBACK_BOTTOM_THRESHOLD));
*elipsis = false;
}
}
/* Private routines end. */
static void pallene_tracer_frameenter(pt_cont_t *cont, pt_frame_t *restrict frame) {
Expand Down Expand Up @@ -266,14 +325,35 @@ static void pallene_tracer_frameexit(pt_cont_t *cont) {
cont->stack = cont->stack->prev;
}
/* Helper macro specific to this function only :). */
#define DBG_PRINT() _dbg_print(buf, &elipsis, &pframes, nframes)
static int pallene_tracer_debug_traceback(lua_State *L) {
const char *message = lua_tostring(L, 1);
fprintf(stderr, "Runtime error: %s\nStack traceback:\n", message);
lua_getfield(L, LUA_REGISTRYINDEX, PALLENE_TRACER_STACK_ENTRY);
pt_frame_t *stack = ((pt_cont_t *) lua_touserdata(L, -1))->stack;
lua_pop(L, 1);
/* Max number of white and black frames. */
int mwhite, mblack;
_countframes(stack, &mwhite, &mblack);
/* Max levels of Lua stack. */
int mlevel = _countlevels(L);
/* Total frames we are going to print. */
/* Black frames are used for switching and we will start from
Lua stack level 1. */
int nframes = mlevel + mwhite - mblack - 1;
/* Amount of frames printed. */
int pframes = 0;
/* Should we print elipsis? */
bool elipsis = nframes > (PALLENE_TRACEBACK_TOP_THRESHOLD
+ PALLENE_TRACEBACK_BOTTOM_THRESHOLD);
/* Buffer to store a single frame line to be printed. */
char buf[1024];
const char *message = lua_tostring(L, 1);
fprintf(stderr, "Runtime error: %s\nStack traceback:\n", message);
lua_Debug ar;
int top = lua_gettop(L);
int level = 1;
Expand All @@ -294,9 +374,10 @@ static int pallene_tracer_debug_traceback(lua_State *L) {
if(lua_tocfunction(L, -1) == check->shared.frame_sig) {
/* Now print all the frames in Pallene stack. */
while(stack != check) {
fprintf(stderr, " %s:%d: in function '%s'\n",
sprintf(buf, " %s:%d: in function '%s'\n",
stack->shared.details->mod_name,
stack->line, stack->shared.details->fn_name);
DBG_PRINT();
stack = stack->prev;
}
Expand All @@ -317,7 +398,8 @@ static int pallene_tracer_debug_traceback(lua_State *L) {
lua_pushfstring(L, "%s", lua_tostring(L, -1));
else lua_pushliteral(L, "<?>");
fprintf(stderr, " C: in function '%s'\n", lua_tostring(L, -1));
sprintf(buf, " C: in function '%s'\n", lua_tostring(L, -1));
DBG_PRINT();
} else {
/* It's a Lua frame. */
Expand All @@ -332,15 +414,17 @@ static int pallene_tracer_debug_traceback(lua_State *L) {
lua_pushfstring(L, "function '%s'", lua_tostring(L, -1));
else lua_pushliteral(L, "function '<?>'");
fprintf(stderr, " %s:%d: in %s\n", ar.short_src,
sprintf(buf, " %s:%d: in %s\n", ar.short_src,
ar.currentline, lua_tostring(L, -1));
DBG_PRINT();
}
lua_settop(L, top);
}
return 0;
}
#undef DBG_PRINT
static pt_cont_t *pallene_tracer_init(lua_State *L) {
pt_cont_t *cont = NULL;
Expand Down

0 comments on commit 2b70297

Please sign in to comment.