Fix debug information about finalizers

The flag CIST_FIN does not mark a finalizer, but the function that was
running when the finalizer was called. (So, the function did not call
the finalizer, but it looks that way in the stack.)
This commit is contained in:
Roberto Ierusalimschy 2021-12-14 12:50:05 -03:00
parent 0bfc572e51
commit 066e0f93c4
5 changed files with 35 additions and 27 deletions

View File

@ -34,8 +34,8 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
static const char *funcnamefromcode (lua_State *L, CallInfo *ci, static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
const char **name); const char **name);
static int currentpc (CallInfo *ci) { static int currentpc (CallInfo *ci) {
@ -317,15 +317,9 @@ static void collectvalidlines (lua_State *L, Closure *f) {
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
if (ci == NULL) /* no 'ci'? */ /* calling function is a known function? */
return NULL; /* no info */ if (ci != NULL && !(ci->callstatus & CIST_TAIL))
else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */ return funcnamefromcall(L, ci->previous, name);
*name = "__gc";
return "metamethod"; /* report it as such */
}
/* calling function is a known Lua function? */
else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
return funcnamefromcode(L, ci->previous, name);
else return NULL; /* no way to find a name */ else return NULL; /* no way to find a name */
} }
@ -597,16 +591,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
** Returns what the name is (e.g., "for iterator", "method", ** Returns what the name is (e.g., "for iterator", "method",
** "metamethod") and sets '*name' to point to the name. ** "metamethod") and sets '*name' to point to the name.
*/ */
static const char *funcnamefromcode (lua_State *L, CallInfo *ci, static const char *funcnamefromcode (lua_State *L, const Proto *p,
const char **name) { int pc, const char **name) {
TMS tm = (TMS)0; /* (initial value avoids warnings) */ TMS tm = (TMS)0; /* (initial value avoids warnings) */
const Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->code[pc]; /* calling instruction */ Instruction i = p->code[pc]; /* calling instruction */
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
*name = "?";
return "hook";
}
switch (GET_OPCODE(i)) { switch (GET_OPCODE(i)) {
case OP_CALL: case OP_CALL:
case OP_TAILCALL: case OP_TAILCALL:
@ -643,6 +631,26 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
return "metamethod"; return "metamethod";
} }
/*
** Try to find a name for a function based on how it was called.
*/
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
const char **name) {
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
*name = "?";
return "hook";
}
else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */
*name = "__gc";
return "metamethod"; /* report it as such */
}
else if (isLua(ci))
return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name);
else
return NULL;
}
/* }====================================================== */ /* }====================================================== */
@ -728,14 +736,14 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
/* /*
** Raise an error for calling a non-callable object. Try to find ** Raise an error for calling a non-callable object. Try to find a name
** a name for the object based on the code that made the call ** for the object based on how it was called ('funcnamefromcall'); if it
** ('funcnamefromcode'); if it cannot get a name there, try 'varinfo'. ** cannot get a name there, try 'varinfo'.
*/ */
l_noret luaG_callerror (lua_State *L, const TValue *o) { l_noret luaG_callerror (lua_State *L, const TValue *o) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
const char *name = NULL; /* to avoid warnings */ const char *name = NULL; /* to avoid warnings */
const char *kind = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL; const char *kind = funcnamefromcall(L, ci, &name);
const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o); const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o);
typeerror(L, o, "call", extra); typeerror(L, o, "call", extra);
} }

2
lgc.c
View File

@ -917,7 +917,7 @@ static void GCTM (lua_State *L) {
L->allowhook = oldah; /* restore hooks */ L->allowhook = oldah; /* restore hooks */
g->gcstp = oldgcstp; /* restore state */ g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc metamethod"); luaE_warnerror(L, "__gc");
L->top--; /* pops error object */ L->top--; /* pops error object */
} }
} }

View File

@ -209,7 +209,7 @@ typedef struct CallInfo {
#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */ #define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */ #define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
#define CIST_FIN (1<<7) /* call is running a finalizer */ #define CIST_FIN (1<<7) /* function "called" a finalizer */
#define CIST_TRAN (1<<8) /* 'ci' has transfer information */ #define CIST_TRAN (1<<8) /* 'ci' has transfer information */
#define CIST_CLSRET (1<<9) /* function is closing tbc variables */ #define CIST_CLSRET (1<<9) /* function is closing tbc variables */
/* Bits 10-12 are used for CIST_RECST (see below) */ /* Bits 10-12 are used for CIST_RECST (see below) */

View File

@ -887,7 +887,7 @@ do -- testing debug info for finalizers
-- create a piece of garbage with a finalizer -- create a piece of garbage with a finalizer
setmetatable({}, {__gc = function () setmetatable({}, {__gc = function ()
local t = debug.getinfo(2) -- get callee information local t = debug.getinfo(1) -- get function information
assert(t.namewhat == "metamethod") assert(t.namewhat == "metamethod")
name = t.name name = t.name
end}) end})

View File

@ -371,7 +371,7 @@ if T then
warn("@on"); warn("@store") warn("@on"); warn("@store")
collectgarbage() collectgarbage()
assert(string.find(_WARN, "error in __gc metamethod")) assert(string.find(_WARN, "error in __gc"))
assert(string.match(_WARN, "@(.-)@") == "expected"); _WARN = false assert(string.match(_WARN, "@(.-)@") == "expected"); _WARN = false
for i = 8, 10 do assert(s[i]) end for i = 8, 10 do assert(s[i]) end