ThePhD / sol2

Sol3 (sol2 v3.0) - a C++ <-> Lua API wrapper with advanced features and top notch performance - is here, and it's great! Documentation:
http://sol2.rtfd.io/
MIT License
4.12k stars 500 forks source link

Strange stack behavior with new_usertype<T>() on g++ debug builds. #1441

Open lhog opened 1 year ago

lhog commented 1 year ago

Sol version v3.3.0 gcc/g++ version gcc-11.1

config defines:

#define LUA_VERSION_NUM 501
#define SOL_USING_CXX_LUA 1
#define SOL_ALL_SAFETIES_ON 1
#define SOL_NO_CHECK_NUMBER_PRECISION 1

I have a piece of code like the following:

const int top = lua_gettop(L);
// make a new table
lua_pushstring(L, "blabla");
lua_newtable(L);
PushEntries(L);
lua_rawset(L, -3);

lua_settop(L, top);
struct A { int x; };
struct B { int y; };
struct C { int z; };

void PushEntries(lua_State* L)
{
std::cout << "ss " << lua_gettop(L) << std::endl;
sol::state_view lua(L);
std::cout << "ss " << lua_gettop(L) << std::endl;
auto tbl = sol::stack::get<sol::table>(L, -1);
std::cout << "ss " << lua_gettop(L) << std::endl;
tbl.new_usertype<A>("A");
std::cout << "ss " << lua_gettop(L) << std::endl;
tbl.new_usertype<B>("B");
std::cout << "ss " << lua_gettop(L) << std::endl;
tbl.new_usertype<C>("C");
std::cout << "ss " << lua_gettop(L) << std::endl;
std::abort();
}

And I get very interesting results:

On MSVC RWDI and Debug as well as on GCC RWDI I get the output I expected:

ss 4
ss 4
ss 4
ss 4
ss 4
ss 4

However on GCC Debug I get something else:

ss 4
ss 4
ss 4
ss 4
ss 5
ss 6

So the stack starts growing after the second call to tbl.new_usertype

if I replace the code above with simple arithmetic types:

std::cout << "ss " << lua_gettop(L) << std::endl;
sol::state_view lua(L);
std::cout << "ss " << lua_gettop(L) << std::endl;
auto gl = sol::stack::get<sol::table>(L, -1);
std::cout << "ss " << lua_gettop(L) << std::endl;
gl.new_usertype<int32_t>("A");
std::cout << "ss " << lua_gettop(L) << std::endl;
gl.new_usertype<float>("B");
std::cout << "ss " << lua_gettop(L) << std::endl;
gl.new_usertype<uint32_t>("C");
std::cout << "ss " << lua_gettop(L) << std::endl;

GCC Debug output is back to norm:

ss 4
ss 4
ss 4
ss 4
ss 4
ss 4

If I modify the code to output the types on stack:

static std::vector<std::string> dumpstack(lua_State *L) {
  std::vector<std::string> trace;
  int top=lua_gettop(L);
  trace.emplace_back(fmt::sprintf("===<stack size = %d>===", top));
  for (int i = top; i >= 1; i--) {
    trace.emplace_back(fmt::sprintf("%d\t%s\t", i, luaL_typename(L,i)));
    switch (lua_type(L, i)) {
      case LUA_TNUMBER:
        trace.emplace_back(fmt::sprintf("%g\n",lua_tonumber(L,i)));
        break;
      case LUA_TSTRING:
        trace.emplace_back(fmt::sprintf("%s\n",lua_tostring(L,i)));
        break;
      case LUA_TBOOLEAN:
        trace.emplace_back(fmt::sprintf("%s\n", (lua_toboolean(L, i) ? "true" : "false")));
        break;
      case LUA_TNIL:
        trace.emplace_back(fmt::sprintf("%s\n", "nil"));
        break;
      default:
        trace.emplace_back(fmt::sprintf("%p\n",lua_topointer(L,i)));
        break;
    }
  }
  return trace;
}

static void printstack(lua_State *L) {
  auto stack = dumpstack(L);
  for (const auto& item : stack) {
    std::cout << item << std::endl;
  }
}
sol::state_view lua(L);
auto tbl = sol::stack::get<sol::table>(L, -1);
printstack(L);
tbl.new_usertype<A>("A");
printstack(L);
tbl.new_usertype<B>("B");
printstack(L);
tbl.new_usertype<C>("C");
printstack(L);

Gives me:

===<stack size = 4>===
4       table
0x55559da30cd0

3       string
blabla

2       table
0x55559da2a868

1       table
0x55559da2e030

===<stack size = 4>===
4       table
0x55559da30cd0

3       string
blabla

2       table
0x55559da2a868

1       table
0x55559da2e030

===<stack size = 4>===
4       table
0x55559da30cd0

3       string
blabla

2       table
0x55559da2a868

1       table
0x55559da2e030

===<stack size = 4>===
4       table
0x55559da30cd0

3       string
blabla

2       table
0x55559da2a868

1       table
0x55559da2e030

on GCC RWDI

And

===<stack size = 4>===
4       table
0x55559d810360

3       string
blabla

2       table
0x55559d809ef8

1       table
0x55559d80d6c0

===<stack size = 4>===
4       table
0x55559d810360

3       string
blabla

2       table
0x55559d809ef8

1       table
0x55559d80d6c0

===<stack size = 5>===
5       table
0x55559d807fa0

4       table
0x55559d810360

3       string
blabla

2       table
0x55559d809ef8

1       table
0x55559d80d6c0

===<stack size = 6>===
6       table
0x55559d807fa0

5       table
0x55559d807fa0

4       table
0x55559d810360

3       string
blabla

2       table
0x55559d809ef8

1       table
0x55559d80d6c0

on GCC DEBUG

Please advise how to debug further.