diff --git a/extension/script/backend/worker/eval/readonly.lua b/extension/script/backend/worker/eval/readonly.lua index 49e01d45..ecce35cd 100644 --- a/extension/script/backend/worker/eval/readonly.lua +++ b/extension/script/backend/worker/eval/readonly.lua @@ -33,6 +33,9 @@ do i = i + 1 end end +if not env and getfenv then + env = getfenv(f) +end do local i = 1 while true do @@ -76,6 +79,9 @@ end local compiled = env and assert(_load(full_source, '=(EVAL)', "t", env)) or assert(_load(full_source, '=(EVAL)')) +if env and setfenv then + setfenv(compiled, env) +end local func = compiled() do local i = 1 diff --git a/extension/script/backend/worker/eval/readwrite.lua b/extension/script/backend/worker/eval/readwrite.lua index 4073c181..12b41473 100644 --- a/extension/script/backend/worker/eval/readwrite.lua +++ b/extension/script/backend/worker/eval/readwrite.lua @@ -42,6 +42,9 @@ do i = i + 1 end end +if not env and getfenv then + env = getfenv(f) +end do local i = 1 while true do @@ -90,6 +93,9 @@ end local compiled = env and assert(_load(full_source, '=(EVAL)', "t", env)) or assert(_load(full_source, '=(EVAL)')) +if env and setfenv then + setfenv(compiled, env) +end local func, update = compiled() local found = {} do diff --git a/extension/script/backend/worker/variables.lua b/extension/script/backend/worker/variables.lua index a42a4874..d8d472af 100644 --- a/extension/script/backend/worker/variables.lua +++ b/extension/script/backend/worker/variables.lua @@ -148,6 +148,13 @@ function special_has.Global(frameId) if eval ~= "_ENV" then eval = "_G" value = rdebug._G + if LUAVERSION == 51 then + local fenv = rdebug.getfenv(info.func) + if fenv and not rdebug.equal(fenv, rdebug._G) then + eval = nil + value = fenv + end + end end if eval == "_G" and globalCache._G then local t = globalCache._G diff --git a/src/luadebug/rdebug_visitor.cpp b/src/luadebug/rdebug_visitor.cpp index a0cd45fe..739e6dad 100644 --- a/src/luadebug/rdebug_visitor.cpp +++ b/src/luadebug/rdebug_visitor.cpp @@ -792,6 +792,19 @@ namespace luadebug::visitor { return 2; } + static int visitor_getfenv(luadbg_State* L, lua_State* hL, protected_area& area) { +#if LUA_VERSION_NUM == 501 + if (!copy_from_dbg(L, hL, area, 1, LUADBG_TFUNCTION)) { + return 0; + } + lua_pop(hL, 1); + refvalue::create(L, 1, refvalue::FENV {}); + return 1; +#else + return 0; +#endif + } + template static int visitor_getmetatable(luadbg_State* L, lua_State* hL, protected_area& area) { area.check_client_stack(2); @@ -1120,6 +1133,7 @@ namespace luadebug::visitor { { "getlocalv", protected_call> }, { "getupvalue", protected_call }, { "getupvaluev", protected_call> }, + { "getfenv", protected_call }, { "getmetatable", protected_call }, { "getmetatablev", protected_call> }, { "getuservalue", protected_call }, diff --git a/src/luadebug/util/refvalue.cpp b/src/luadebug/util/refvalue.cpp index 6053e87f..ec644a87 100644 --- a/src/luadebug/util/refvalue.cpp +++ b/src/luadebug/util/refvalue.cpp @@ -328,6 +328,25 @@ namespace luadebug::refvalue { } } + template <> + int eval(FENV& v, lua_State* hL, value* parent) { + int t = eval(parent, hL); + if (t == LUA_TNONE) + return LUA_TNONE; + if (t != LUA_TFUNCTION) { + lua_pop(hL, 1); + return LUA_TNONE; + } +#if LUA_VERSION_NUM == 501 + lua_getfenv(hL, -1); + lua_replace(hL, -2); + return lua_type(hL, -1); +#else + lua_pop(hL, 1); + return LUA_TNONE; +#endif + } + int eval(value* v, lua_State* hL) { return visit([hL, v](auto&& arg) { return eval(arg, hL, v + 1); }, *v); } diff --git a/src/luadebug/util/refvalue.h b/src/luadebug/util/refvalue.h index 7d77f371..d2902c6e 100644 --- a/src/luadebug/util/refvalue.h +++ b/src/luadebug/util/refvalue.h @@ -53,6 +53,7 @@ namespace luadebug::refvalue { struct USERDATA_VAL { unsigned int index; }; + struct FENV {}; using value = variant< FRAME_LOCAL, FRAME_FUNC, @@ -66,7 +67,8 @@ namespace luadebug::refvalue { TABLE_HASH_KEY, TABLE_HASH_VAL, USERDATA_KEY, - USERDATA_VAL>; + USERDATA_VAL, + FENV>; static_assert(std::is_trivially_copyable_v); template @@ -102,6 +104,8 @@ namespace luadebug::refvalue { struct allow_as_child : public std::true_type {}; template <> struct allow_as_child : public std::true_type {}; + template <> + struct allow_as_child : public std::true_type {}; int eval(value* v, lua_State* hL); bool assign(value* v, lua_State* hL);