Skip to content

Commit

Permalink
Fix lua_*upvalue() when upvalue names aren't in debug info (#787)
Browse files Browse the repository at this point in the history
`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 <[email protected]>
  • Loading branch information
HaroldCindy and HaroldCindy authored Jan 18, 2023
1 parent a5c6a38 commit 729bc44
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 1 deletion.
4 changes: 3 additions & 1 deletion VM/src/lapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1285,10 +1285,12 @@ static const char* aux_upvalue(StkId fi, int n, TValue** val)
else
{
Proto* p = f->l.p;
if (!(1 <= n && n <= p->sizeupvalues))
if (!(1 <= n && n <= p->nups)) // not a valid upvalue
return NULL;
TValue* r = &f->l.uprefs[n - 1];
*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]);
}
}
Expand Down
28 changes: 28 additions & 0 deletions tests/Conformance.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

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")
{
extern unsigned int luaS_hash(const char* str, size_t len); // internal function, declared in lstring.h - not exposed via lua.h
Expand Down
13 changes: 13 additions & 0 deletions tests/conformance/ndebug_upvalues.lua
Original file line number Diff line number Diff line change
@@ -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'

0 comments on commit 729bc44

Please sign in to comment.