Upvalues: replace upvalue only if it's equal to _G (#110)

This commit is contained in:
mihacooper 2018-10-18 02:08:35 +03:00 committed by Ilia
parent c5d94ec465
commit 2e4e219b85
5 changed files with 22 additions and 74 deletions

View File

@ -2,28 +2,6 @@
namespace effil {
namespace {
bool allowTableUpvalues(const sol::optional<bool>& newValue = sol::nullopt) {
static std::atomic_bool value(true);
if (newValue)
return value.exchange(newValue.value());
return value;
}
} // anonymous
sol::object luaAllowTableUpvalues(sol::this_state state, const sol::stack_object& value) {
if (value.valid()) {
REQUIRE(value.get_type() == sol::type::boolean) << "bad argument #1 to 'effil.allow_table_upvalues' (boolean expected, got " << luaTypename(value) << ")";
return sol::make_object(state, allowTableUpvalues(value.template as<bool>()));
}
else {
return sol::make_object(state, allowTableUpvalues());
}
}
Function::Function(const sol::function& luaObject) {
assert(luaObject.valid());
assert(luaObject.get_type() == sol::type::function);
@ -38,30 +16,29 @@ Function::Function(const sol::function& luaObject) {
ctx_->function = dumpFunction(luaObject);
ctx_->upvalues.resize(dbgInfo.nups);
#if LUA_VERSION_NUM > 501
ctx_->envUpvaluePos = 0; // means no _ENV upvalue
ctx_->envUpvaluePos = 0; // means no _G upvalue
lua_pushglobaltable(state);
const auto gTable = sol::stack::pop<sol::table>(state);
#endif // LUA_VERSION_NUM > 501
for (unsigned char i = 1; i <= dbgInfo.nups; ++i) {
const char* valueName = lua_getupvalue(state, -1, i); // push value on stack
(void)valueName; // get rid of 'unused' warning for Lua5.1
assert(valueName != nullptr);
#if LUA_VERSION_NUM > 501
if (strcmp(valueName, "_ENV") == 0) { // do not serialize _ENV
if (gTable == sol::stack::get<sol::table>(state)) { // do not serialize _G
sol::stack::pop<sol::object>(state);
ctx_->envUpvaluePos = i;
continue;
}
#endif // LUA_VERSION_NUM > 501
const auto& upvalue = sol::stack::pop<sol::object>(state); // pop from stack
if (!allowTableUpvalues() && upvalue.get_type() == sol::type::table) {
sol::stack::pop<sol::object>(state);
throw effil::Exception() << "bad function upvalue #" << (int)i << " (table is disabled by effil.allow_table_upvalues)";
}
StoredObject storedObject;
try {
const auto& upvalue = sol::stack::pop<sol::object>(state);
storedObject = createStoredObject(upvalue);
assert(storedObject.get() != nullptr);
}
@ -87,8 +64,8 @@ sol::object Function::loadFunction(lua_State* state) {
for(size_t i = 0; i < ctx_->upvalues.size(); ++i) {
#if LUA_VERSION_NUM > 501
if (ctx_->envUpvaluePos == i + 1) {
lua_rawgeti(state, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); // push _ENV to stack
lua_setupvalue(state, -2, i + 1); // pop _ENV and set as upvalue
lua_pushglobaltable(state); // push _G to stack
lua_setupvalue(state, -2, i + 1); // pop _G and set as upvalue
continue;
}
#endif // LUA_VERSION_NUM > 501

View File

@ -7,8 +7,6 @@
namespace effil {
sol::object luaAllowTableUpvalues(sol::this_state state, const sol::stack_object&);
class FunctionData : public GCData {
public:
std::string function;

View File

@ -107,7 +107,6 @@ int luaopen_effil(lua_State* L) {
"pairs", SharedTable::globalLuaPairs,
"ipairs", SharedTable::globalLuaIPairs,
"size", luaSize,
"allow_table_upvalues", luaAllowTableUpvalues,
"hardware_threads", std::thread::hardware_concurrency,
sol::meta_function::index, luaIndex
);

View File

@ -122,11 +122,6 @@ local function generate_tests()
-- effil.gc.step
test.type_mismatch.input_types_mismatch_p(1, "number", "gc.step", type_instance)
end
if typename ~= "boolean" then
-- effil.allow_table_upvalue
test.type_mismatch.input_types_mismatch_p(1, "boolean", "allow_table_upvalues", type_instance)
end
end
-- Below presented tests which support everything except coroutines
@ -155,6 +150,5 @@ end
generate_tests()
test.type_mismatch.gc_checks_after_tests = function()
effil.allow_table_upvalues(true)
default_tear_down()
end

View File

@ -60,7 +60,7 @@ test.upvalues.check_table = function()
test.equal(ret, "effil.table: value")
end
test.upvalues.check_env = function()
test.upvalues.check_global_env = function()
local obj1 = 13 -- local
obj2 = { key = "origin" } -- global
local obj3 = 79 -- local
@ -81,39 +81,19 @@ test.upvalues.check_env = function()
test.equal(ret, "13, local, 79")
end
local function check_works(should_work)
local obj = { key = "value"}
local function worker()
return obj.key
if LUA_VERSION > 51 then
test.upvalues.check_custom_env = function()
local function create_foo()
local _ENV = { key = 'value' }
return function()
return key
end
end
local ret, err = pcall(effil.thread(worker))
if ret then
err:wait()
end
test.equal(ret, should_work)
if not should_work then
test.equal(err, "effil.thread: bad function upvalue #1 (table is disabled by effil.allow_table_upvalues)")
end
local foo = create_foo()
local ret = effil.thread(foo)():get()
test.equal(ret, 'value')
end
test.upvalues_table.tear_down = function()
effil.allow_table_upvalues(true)
default_tear_down()
end
test.upvalues_table.disabling_table_upvalues = function()
test.equal(effil.allow_table_upvalues(), true)
-- works by default
check_works(true)
-- disable
test.equal(effil.allow_table_upvalues(false), true)
check_works(false)
test.equal(effil.allow_table_upvalues(), false)
-- enable back
test.equal(effil.allow_table_upvalues(true), false)
check_works(true)
test.equal(effil.allow_table_upvalues(), true)
end
end -- LUA_VERSION > 51