You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is not a bug report nor a feature request.
The problem maybe simple for you guys but really drive me nuts, that how to make sol::thread run in sandbox.
Let me re-state it:
We have one lua state to interact with thousands of senders:
sol::state lua;
lua.open_libraries();
lua.script_file("user_defined_functions_and_variables.lua");
create_thousands_of_threads(lua); // one thread per senderwhile(!quit){
auto [event, event_sender] = wait_event();
auto &th = find_thread(lua, event_sender);
th.resume(event);
}
The lua state owns thousands of thread/coroutine, but this event-driven is sequential, means thread/coroutine will sequentially get the event to drive the yield/resume.
And each thread/coroutine yield/resume with their own environment, means:
Every thread/coroutine has a localized global variable table _G_sandbox, and it should override the default _G.
When thread/coroutine read-accesses a global variable, it firstly try to find in the _G_sandbox, if not find then try to find in _G, if still not find, return nil.
When thread/coroutine write-access to a global variable, it firstly try to find in the _G_sandbox, access it if found, else
if the accessing function is user-defined, create new global variable in _G_sandbox.
if this access is from lua standard libraries, report error and crash out. (optional if hard to implement)
When you finish the read, you know I want each thread/coroutine to run in sandbox that won't interfere with each other. They can read-access existing global variables, but shall not write/modify it, alternatively it should be in a localized _G_sandbox.
I currently have an implementation, looks working (or has bug I am not aware of), question is:
is this the supposed way for sol2 to implement it?
it uses raw lua functions lua_rawgeti/lua_rawseti not through sol2 interface, can this mess up any sol2 internal states?
Do we have better/simplier way to implement with sol2?
#include<bits/stdc++.h>
#include"sol/sol.hpp"voidcheckError(const sol::protected_function_result &pfr)
{
if(pfr.valid()){
return;
}
const sol::error err = pfr;
std::stringstream errStream(err.what());
std::string errLine;
while(std::getline(errStream, errLine, '\n')){
std::cout << "callback error: " << errLine << std::endl;
}
}
structLuaThreadRunner
{
sol::thread runner;
sol::coroutine callback;
LuaThreadRunner(sol::state &lua, const std::string &entry)
: runner(sol::thread::create(lua.lua_state()))
, callback(sol::state_view(runner.state())[entry])
{}
};
intmain()
{
sol::state lua;
lua.open_libraries();
lua.script(R"( local _G = _G local error = error local coroutine = coroutine local _G_sandbox = {} function clearTLSTable() local threadId, inMainThread = coroutine.running() if inMainThread then error('call clearTLSTable in main thread') else _G_sandbox[threadId] = nil end end replaceEnv_metatable = { __index = function(table, key) local threadId, inMainThread = coroutine.running() if not inMainThread then if _G_sandbox[threadId] ~= nil and _G_sandbox[threadId][key] ~= nil then return _G_sandbox[threadId][key] end end return _G[key] end, __newindex = function(table, key, value) local threadId, inMainThread = coroutine.running() if inMainThread then _G[key] = value else if _G_sandbox[threadId] == nil then _G_sandbox[threadId] = {} end _G_sandbox[threadId][key] = value end end })");
sol::environment replaceEnv(lua, sol::create);
replaceEnv[sol::metatable_key] = sol::table(lua["replaceEnv_metatable"]);
// idea from: https://blog.rubenwardy.com/2020/07/26/sol3-script-sandbox/// set replaceEnv as default environment, otherwise I don't know how to setup replaceEnv to thread/coroutinelua_rawgeti(lua.lua_state(), LUA_REGISTRYINDEX, replaceEnv.registry_index());
lua_rawseti(lua.lua_state(), LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
lua.script(R"( function coth_main(runner) local threadId, mainThread = coroutine.running() if mainThread then error('coth_main(runner) called in main thread', runner) end -- test require -- require should still work and accesses global variable: package local mod = require('io') print(mod) coroutine.yield() counter = 0 -- localized global varible tested counterMax = 10 -- while counter < counterMax do print(string.format('runner %d counter %d, you can resume %d more times', runner, counter, counterMax - counter - 1)) counter = counter + 1 coroutine.yield() end clearTLSTable() end)");
LuaThreadRunner runner1(lua, "coth_main");
checkError(runner1.callback(1));
LuaThreadRunner runner2(lua, "coth_main");
checkError(runner2.callback(2));
constauto fnResume = [](auto &callback, intindex)
{
if(callback){
checkError(callback());
}
else{
std::cout << "runner " << index << " has exited" << std::endl;
}
};
while(runner1.callback || runner2.callback){
int event_from = 0;
std::cout << "wait event from: ";
std::cin >> event_from;
switch(event_from){
case1: fnResume(runner1.callback, 1); break;
case2: fnResume(runner2.callback, 2); break;
default: std::cout << "no runner " << event_from << std::endl;
}
}
return0;
}
The text was updated successfully, but these errors were encountered:
I am a lua newbie.
This is not a bug report nor a feature request.
The problem maybe simple for you guys but really drive me nuts, that how to make
sol::thread
run in sandbox.I think many people trying to figure out this in a gentle way, as following links:
https://blog.rubenwardy.com/2020/07/26/sol3-script-sandbox/
https://stackoverflow.com/a/24358483/1490269
https://stackoverflow.com/questions/57030514/changing-the-env-of-a-lua-thread-using-c-api
Let me re-state it:
We have one lua state to interact with thousands of senders:
The lua state owns thousands of
thread/coroutine
, but this event-driven is sequential, meansthread/coroutine
will sequentially get the event to drive the yield/resume.And each
thread/coroutine
yield/resume with their own environment, means:thread/coroutine
has a localized global variable table_G_sandbox
, and it should override the default_G
.thread/coroutine
read-accesses a global variable, it firstly try to find in the_G_sandbox
, if not find then try to find in_G
, if still not find, returnnil
.thread/coroutine
write-access to a global variable, it firstly try to find in the_G_sandbox
, access it if found, else_G_sandbox
.When you finish the read, you know I want each
thread/coroutine
to run in sandbox that won't interfere with each other. They can read-access existing global variables, but shall not write/modify it, alternatively it should be in a localized_G_sandbox
.I currently have an implementation, looks working (or has bug I am not aware of), question is:
lua_rawgeti/lua_rawseti
not through sol2 interface, can this mess up any sol2 internal states?The text was updated successfully, but these errors were encountered: