Changeset

11177:37dc2a6144d1 0.11

util.debug: Fix locals being reported under wrong stack frame in some cases (+tests!!)
author Matthew Wild <mwild1@gmail.com>
date Fri, 16 Oct 2020 13:38:04 +0100
parents 11175:235537247aa3
children 11178:44bcddecf1b5 11189:0ff148362a3d
files spec/util_debug_spec.lua util/debug.lua
diffstat 2 files changed, 94 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spec/util_debug_spec.lua	Fri Oct 16 13:38:04 2020 +0100
@@ -0,0 +1,93 @@
+local dbg = require "util.debug";
+
+describe("util.debug", function ()
+	describe("traceback()", function ()
+		it("works", function ()
+			local tb = dbg.traceback();
+			assert.is_string(tb);
+		end);
+	end);
+	describe("get_traceback_table()", function ()
+		it("works", function ()
+			local count = 0;
+			-- MUST stay in sync with the line numbers of these functions:
+			local f1_defined, f3_defined = 43, 15;
+			local function f3(f3_param) --luacheck: ignore 212/f3_param
+				count = count + 1;
+
+				for i = 1, 2 do
+					local tb = dbg.get_traceback_table(i == 1 and coroutine.running() or nil, 0);
+					assert.is_table(tb);
+					--print(dbg.traceback(), "\n\n\n", require "util.serialization".serialize(tb, { fatal = false, unquoted = true}));
+					local found_f1, found_f3;
+					for _, frame in ipairs(tb) do
+						if frame.info.linedefined == f1_defined then
+							assert.equal(0, #frame.locals);
+							assert.equal("f2", frame.upvalues[1].name);
+							assert.equal("f1_upvalue", frame.upvalues[2].name);
+							found_f1 = true;
+						elseif frame.info.linedefined == f3_defined then
+							assert.equal("f3_param", frame.locals[1].name);
+							found_f3 = true;
+						end
+					end
+					assert.is_true(found_f1);
+					assert.is_true(found_f3);
+				end
+			end
+			local function f2()
+				local f2_local = "hello";
+				return f3(f2_local);
+			end
+			local f1_upvalue = "upvalue1";
+			local function f1()
+				f2(f1_upvalue);
+			end
+
+			-- ok/err are caught and re-thrown so that
+			-- busted gets to handle them in its own way
+			local ok, err;
+			local function hook()
+				debug.sethook();
+				ok, err = pcall(f1);
+			end
+
+			-- Test the traceback is correct in various
+			-- types of caller environments
+
+			-- From a Lua hook
+			debug.sethook(hook, "crl", 1);
+			local a = string.sub("abcdef", 3, 4);
+			assert.equal("cd", a);
+			debug.sethook();
+			assert.equal(1, count);
+
+			if not ok then
+				error(err);
+			end
+			ok, err = nil, nil;
+
+			-- From a signal handler (C hook)
+			require "util.signal".signal("SIGUSR1", hook);
+			require "util.signal".raise("SIGUSR1");
+			assert.equal(2, count);
+
+			if not ok then
+				error(err);
+			end
+			ok, err = nil, nil;
+
+			-- Inside a coroutine
+			local co = coroutine.create(function ()
+				hook();
+			end);
+			coroutine.resume(co);
+
+			if not ok then
+				error(err);
+			end
+
+			assert.equal(3, count);
+		end);
+	end);
+end);
--- a/util/debug.lua	Thu Oct 15 17:21:58 2020 +0200
+++ b/util/debug.lua	Fri Oct 16 13:38:04 2020 +0100
@@ -104,7 +104,7 @@
 		levels[(level-start_level)+1] = {
 			level = level;
 			info = info;
-			locals = get_locals_table(thread, level+(thread and 0 or 1));
+			locals = get_locals_table(thread, level+1);
 			upvalues = get_upvalues_table(info.func);
 		};
 	end