Lua注册表损坏并将其存储在0x3FF00000?

问题描述

所以。这是一个傻瓜。我正在使用Lua注册表(也称为LUA_REGISTRYINDEX)存储我稍后要从C调用的Lua回调函数。这非常简单,这是我用于存储和检索Lua回调的实用函数:


bool store_function(lua_State *L,int *storage)
{
    if(*storage) {
        luaL_unref(L,LUA_REGISTRYINDEX,*storage);
    }

    if(lua_type(L,-1) == LUA_TFUNCTION)
    {
        *storage = luaL_ref(L,LUA_REGISTRYINDEX);
        return true;
    }
    else if(lua_type(L,-1) == LUA_TNIL)
    {
        *storage = 0;
        return false;
    }
    else
    {
        luaL_error(L,"Invalid function");
        return false;
    }
}
bool get_function(lua_State *L,int storage)
{
    if(storage == 0)
    {
        return false;
    }
    lua_rawgeti(L,storage);
    if(lua_isnil(L,-1))
    {
        lua_pop(L,1);
        return false;
    }
    return true;
}

({storage指向我将索引存储到正确的函数指针的全局int)。

现在,这几乎总是很有效。但是,有时,我的回调混杂在一起,并调用了错误的回调,从而导致热闹错误。

由于它是如此断断续续,因此花了几个月的时间才能确定下来。我已经在自己的代码和lua的标准库(实际上是luajit,但lauxlib代码大多是lua 5.1的复制粘贴)中添加了调试打印。

console with weird indexes

我开始将索引打印到注册表中,在该注册表中,我的回调最终结束,并注意到它们通常位于索引12、13、14及其附近,除了发生此错误外,此时索引为1072693248。十六进制为0x3FF00000,二进制为00111111111100000000000000000000。那不是巧合。

看起来at the source for luaL_ref,很明显它应该只使用连续的整数(还要重用旧的插槽),而且我怀疑我的注册表中是否包含十亿个对象。

更多跟踪。我将此补丁添加到了luajit:

diff --git a/src/lib_aux.c b/src/lib_aux.c
index 2682a38..71b68dc 100644
--- a/src/lib_aux.c
+++ b/src/lib_aux.c
@@ -276,6 +276,7 @@ LUALIB_API void luaL_buffinit(lua_State *L,luaL_Buffer *B)
 LUALIB_API int luaL_ref(lua_State *L,int t)
 {
   int ref;
+  const char* how = "free element";
   t = abs_index(L,t);
   if (lua_isnil(L,-1)) {
     lua_pop(L,1);  /* remove from stack */
@@ -288,9 +289,11 @@ LUALIB_API int luaL_ref(lua_State *L,int t)
     lua_rawgeti(L,t,ref);  /* remove it from list */
     lua_rawseti(L,FREELIST_REF);  /* (t[FREELIST_REF] = t[ref]) */
   } else {  /* no free elements */
+    how = "created ref";
     ref = (int)lua_objlen(L,t);
     ref++;  /* create new reference */
   }
+  printf("refSetting in table %d (%s): at ref %d (%s)\n",t == LUA_REGISTRYINDEX ? "registry" : "user",ref,how);
   lua_rawseti(L,ref);
   return ref;
 }
diff --git a/src/lj_api.c b/src/lj_api.c
index d17a575..bb7b9dd 100644
--- a/src/lj_api.c
+++ b/src/lj_api.c
@@ -996,6 +996,13 @@ LUA_API void lua_rawset(lua_State *L,int idx)

 LUA_API void lua_rawseti(lua_State *L,int idx,int n)
 {
+  if (idx == -10000) {
+    printf("rawseti in registry[%d] = %d / %.2f\n",n,lua_tointeger(L,-1),lua_tonumber(L,-1));
+    if (lua_tointeger(L,-1) == 1072693248) {
+      printf("\n\noh shit!\n\n");
+      lua_assert(lua_tointeger(L,-1) != 1072693248);
+    }
+  }
   GCtab *t = tabV(index2adr(L,idx));
   TValue *dst,*src;
   api_checknelems(L,1);

以及更高版本,即使发生这种情况,也可以使用堆栈跟踪打印。快进一个月,就会触发:

stack 2

stack 3

我的解释是,表的自由列表索引(它将下一个可重复使用的索引存储在其自身的索引0中)最终变得无用,然后整个注册表就停止工作了。

是内存堆损坏了吗?我的lua有毛病吗?我C语言中的错误?十岁的lua lauxlib中的错误?我不知道。

什么是0x3FF00000?值为1.0000的两倍的指数。但是为什么在那里呢?它还用于在cJSON(同一过程中的另一个C库)中解码UTF-16。

我的代码:

任何线索和猜测将不胜感激。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...