求大神帮忙看下:tolua++在push的时候是否有一个潜在的bug?

void tolua_pushusertype_internal (lua_State* L, void* value, const char* type, int addToRoot)
{
if (value == NULL)
lua_pushnil(L);
else
{
luaL_getmetatable(L, type); /* stack: mt /
if (lua_isnil(L, -1)) { /
NOT FOUND metatable /
lua_pop(L, 1);
return;
}
lua_pushstring(L,“tolua_ubox”);
lua_rawget(L,-2); /
stack: mt ubox */
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
lua_pushstring(L, “tolua_ubox”);
lua_rawget(L, LUA_REGISTRYINDEX);
};

    lua_pushlightuserdata(L,value);                             /* stack: mt ubox key<value> */
    lua_rawget(L,-2);                                           /* stack: mt ubox ubox */
    
    if (lua_isnil(L,-1))
    {
        lua_pop(L,1);                                           /* stack: mt ubox */
        lua_pushlightuserdata(L,value);
        *(void**)lua_newuserdata(L,sizeof(void *)) = value;     /* stack: mt ubox value newud */
        lua_pushvalue(L,-1);                                    /* stack: mt ubox value newud newud */
        lua_insert(L,-4);                                       /* stack: mt newud ubox value newud */
        lua_rawset(L,-3);                  /* ubox = newud, stack: mt newud ubox */
        lua_pop(L,1);                                           /* stack: mt newud */
        /*luaL_getmetatable(L,type);*/
        lua_pushvalue(L, -2);                                   /* stack: mt newud mt */
        lua_setmetatable(L,-2);                      /* update mt, stack: mt newud */

#ifdef LUA_VERSION_NUM
lua_pushvalue(L, TOLUA_NOPEER); /* stack: mt newud peer /
lua_setfenv(L, -2); /
stack: mt newud /
#endif
}
else
{
/
check the need of updating the metatable to a more specialized class /
lua_insert(L,-2); /
stack: mt ubox ubox /
lua_pop(L,1); /
stack: mt ubox /
lua_pushstring(L,“tolua_super”);
lua_rawget(L,LUA_REGISTRYINDEX); /
stack: mt ubox super /
lua_getmetatable(L,-2); /
stack: mt ubox super mt /
lua_rawget(L,-2); /
stack: mt ubox super super /
if (lua_istable(L,-1))
{
lua_pushstring(L,type); /
stack: mt ubox super super type /
lua_rawget(L,-2); /
stack: mt ubox super super flag /
if (lua_toboolean(L,-1) == 1) /
if true /
{
lua_pop(L,3); /
mt ubox*/
lua_remove(L, -2);
return;
}
}
/* type represents a more specilized type */
/luaL_getmetatable(L,type); // stack: mt ubox super super flag mt /
lua_pushvalue(L, -5); /
stack: mt ubox super super flag mt /
lua_setmetatable(L,-5); /
stack: mt ubox super super flag /
lua_pop(L,3); /
stack: mt ubox /
}
lua_remove(L, -2); /
stack: ubox
/

    if (0 != addToRoot)
    {
        lua_pushvalue(L, -1);
        tolua_add_value_to_root(L, value);
    }
} 

}

假设super由于某种原因不是一个table 那栈上面不是就只有4个元素了么?(stack: mt ubox super super)
这时候在pushvalue(L, -5),是不是就会有问题?

求大神帮忙看下。

为什么 super 不是 table ?

我只是简单的从代码段上进行判断 如果一定是table 或者不为nil 那这句判断又有什么作用呢? if (lua_istable(L,-1))

另外最近再给项目做lua绑定的时候 发现3.0调用clang进行语法解析 然后生成代码 但是发现好多代码通不过clang的编译 结果只好弃用3.0的工具了。。。

即使super不是 table,取回来的值也占一个元素的位置吧

   /*luaL_getmetatable(L,type);             // stack: mt ubox super super flag mt */

注意这句话源码是注释掉的

现在没时间具体分析代码,简单看了一下,这里如果mt一般都是table,通常走的是上面的代码。而不是table的情况,应该是遇到没有super的时候,这时会将mt初始设置成一个table。栈上是有5个元素的,请不要只看if判断语句块里的代码,前面还有其他的代码的。

lua_rawget(L,-2); /* stack: mt ubox super super /
假设super为nil或不是table 后面不走近table 按照上面一步的情况 栈上四个元素 mt ubox super super
/
type represents a more specilized type */
/*luaL_getmetatable(L,type); // stack: mt ubox super super flag mt /
lua_pushvalue(L, -5); /
stack: mt ubox super super flag mt */
然后luaL_getmetatable(L,type); 这句话源码中被注释掉
在lua_pushvalue(L, -5); 调用前栈上应该就是四个元素 我不明白您说的“这时会将mt初始设置成一个table。”是在哪里。
源码之所以能够正确 前提就是一定存在super 并且一定是一个以type为键 flag为值得table
不纠结假设的正确性 从代码表面流程来看 这段代码一定是有问题的

tolua++供c++调用的源代码并不多 大头很多是在解析pkg层面 阅读源码的难点无非就是对lua的api的熟悉 只要把每句话的堆栈都写好 就可以完全读懂
说白了就是考验一个人的时间和耐心
我近期准备写一个简单的demo 断点跟踪把源码通读一遍 就什么都清楚了

你说得很不错,其实读lua的api就是需要耐心。
刚才有时间坐下来仔细读代码了。可以确认你说得不错,如果if (lua_istable(L,-1))这个判断走不进去,flag没取到,下面那句又注释了,确实会有问题。我原来只浏览了一下注释里的栈变化就下结论,确实轻率了。
tolua++有Bug也是正常的吧。我最近也在读它的代码,楼主有什么心得的话可以一起交流一下,呵呵。