mirror of
https://github.com/luau-lang/luau.git
synced 2024-12-12 21:10:37 +00:00
Fix lua_*upvalue() when upvalue names aren't in debug info (#787)
`lua_getupvalue()` and `lua_setupvalue()` don't behave as expected when working with Lua closure whose `Proto` has no debug info. The code currently uses `sizeupvalues` to do bounds checking of upvalue indices, but that's the size of the upvalue _names_ array. It will always be `0` if the `Proto` doesn't have debug info. This uses `nups` instead, and just returns `""` as the upvalue name if we don't have one, same as for C closures. Co-authored-by: Harold Cindy <HaroldCindy@users.noreply.github.com>
This commit is contained in:
parent
a5c6a38b10
commit
729bc44729
3 changed files with 44 additions and 1 deletions
|
@ -1285,10 +1285,12 @@ static const char* aux_upvalue(StkId fi, int n, TValue** val)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Proto* p = f->l.p;
|
Proto* p = f->l.p;
|
||||||
if (!(1 <= n && n <= p->sizeupvalues))
|
if (!(1 <= n && n <= p->nups)) // not a valid upvalue
|
||||||
return NULL;
|
return NULL;
|
||||||
TValue* r = &f->l.uprefs[n - 1];
|
TValue* r = &f->l.uprefs[n - 1];
|
||||||
*val = ttisupval(r) ? upvalue(r)->v : r;
|
*val = ttisupval(r) ? upvalue(r)->v : r;
|
||||||
|
if (!(1 <= n && n <= p->sizeupvalues)) // don't have a name for this upvalue
|
||||||
|
return "";
|
||||||
return getstr(p->upvalues[n - 1]);
|
return getstr(p->upvalues[n - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -693,6 +693,34 @@ TEST_CASE("Debugger")
|
||||||
CHECK(stephits > 100); // note; this will depend on number of instructions which can vary, so we just make sure the callback gets hit often
|
CHECK(stephits > 100); // note; this will depend on number of instructions which can vary, so we just make sure the callback gets hit often
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("NDebugGetUpValue")
|
||||||
|
{
|
||||||
|
lua_CompileOptions copts = defaultOptions();
|
||||||
|
copts.debugLevel = 0;
|
||||||
|
// Don't optimize away any upvalues
|
||||||
|
copts.optimizationLevel = 0;
|
||||||
|
|
||||||
|
runConformance(
|
||||||
|
"ndebug_upvalues.lua",
|
||||||
|
nullptr,
|
||||||
|
[](lua_State* L) {
|
||||||
|
lua_checkstack(L, LUA_MINSTACK);
|
||||||
|
|
||||||
|
// push the second frame's closure to the stack
|
||||||
|
lua_Debug ar = {};
|
||||||
|
REQUIRE(lua_getinfo(L, 1, "f", &ar));
|
||||||
|
|
||||||
|
// get the first upvalue
|
||||||
|
const char* u = lua_getupvalue(L, -1, 1);
|
||||||
|
REQUIRE(u);
|
||||||
|
// upvalue name is unknown without debug info
|
||||||
|
CHECK(strcmp(u, "") == 0);
|
||||||
|
CHECK(lua_tointeger(L, -1) == 5);
|
||||||
|
lua_pop(L, 2);
|
||||||
|
},
|
||||||
|
nullptr, &copts, /* skipCodegen */ false);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("SameHash")
|
TEST_CASE("SameHash")
|
||||||
{
|
{
|
||||||
extern unsigned int luaS_hash(const char* str, size_t len); // internal function, declared in lstring.h - not exposed via lua.h
|
extern unsigned int luaS_hash(const char* str, size_t len); // internal function, declared in lstring.h - not exposed via lua.h
|
||||||
|
|
13
tests/conformance/ndebug_upvalues.lua
Normal file
13
tests/conformance/ndebug_upvalues.lua
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
-- This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
|
-- This tests that the lua_*upval() APIs work correctly even with debug info disabled
|
||||||
|
local foo = 5
|
||||||
|
function clo_test()
|
||||||
|
-- so `foo` gets captured as an upval
|
||||||
|
print(foo)
|
||||||
|
-- yield so we can look at clo_test's upvalues
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
|
||||||
|
clo_test()
|
||||||
|
|
||||||
|
return 'OK'
|
Loading…
Reference in a new issue