Lua注册表损坏,并将内容存储在0x3FF00000?

Lua注册表损坏,并将内容存储在0x3FF00000?,lua,ffi,luajit,Lua,Ffi,Luajit,所以。这一个真是太棒了。我使用Lua注册表(akaLua\u REGISTRYINDEX)来存储我的Lua回调函数,稍后我想从C调用这些函数。这非常简单,下面是我用于存储和检索Lua回调的实用函数: bool存储函数(lua\u状态*L,int*存储) { 如果(*存储){ LUA_unref(L,LUA_注册表索引,*存储); } if(lua_类型(L,-1)=lua_函数) { *存储=luaL\U ref(L,LUA\U注册表索引); 返回true; } else if(lua_typ

所以。这一个真是太棒了。我使用Lua注册表(aka
Lua\u REGISTRYINDEX
)来存储我的Lua回调函数,稍后我想从C调用这些函数。这非常简单,下面是我用于存储和检索Lua回调的实用函数:


bool存储函数(lua\u状态*L,int*存储)
{
如果(*存储){
LUA_unref(L,LUA_注册表索引,*存储);
}
if(lua_类型(L,-1)=lua_函数)
{
*存储=luaL\U ref(L,LUA\U注册表索引);
返回true;
}
else if(lua_type(L,-1)=lua_TNIL)
{
*存储=0;
返回false;
}
其他的
{
luaL_错误(L,“无效函数”);
返回false;
}
}
bool get_函数(lua_State*L,int存储)
{
如果(存储==0)
{
返回false;
}
lua_rawgeti(L、lua_注册表索引、存储);
if(lua_isnil(L,-1))
{
卢厄波普(L,1);
返回false;
}
返回true;
}
storage
指向一个全局int,在这里我将索引存储到正确的函数指针)

现在,这几乎总是很有效。然而,有时,我的回调会混淆,调用错误的回调,导致搞笑的bug

因为它是如此的断断续续,所以花了好几个月的时间才确定下来。我在自己的代码和lua的标准库中添加了调试打印(实际上是luajit,但lauxlib代码主要是Lua5.1的复制粘贴)

我开始将索引打印到我的回调结束的注册表中,并注意到它们通常位于索引12、13、14及其附近,除非出现此错误,此时它位于索引1072693248。十六进制为0x3FF00000,二进制为00111111100000000000000。这不可能是巧合

看,很明显,它应该只使用顺序整数(再加上重用旧插槽),我怀疑我的注册表包含超过十亿个对象

更多的追踪。我将此修补程序添加到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, t, 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, t == LUA_REGISTRYINDEX ? "registry" : "user", ref, how);
   lua_rawseti(L, t, 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);
以及更高版本,即使发生这种情况,也会使用堆栈跟踪打印。快进一个月,它会触发:

我的解释是,表的freelist索引(它将下一个可重用索引存储在自身的索引0处)最终会变成垃圾,然后整个注册表就会停止工作

是内存堆损坏吗?我的lua里有只虫子?我的C中有一个bug?十岁的lua lauxlib身上的虫子?我不知道

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

我的代码:


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

您使用的是什么版本的LuaJIT?您是否尝试过使用基于当前2.1分支的LuaJIT?对表进行了罕见的错误修复,看起来可能是您的错误。可能
store\u函数(lua\u State*L,int*storage)
是在初始化错误的
*存储
包含垃圾
3FF00000
的情况下调用的。尝试分析
lua_rawseti(L,-10000,0x3FF00000)
的第一次调用的回溯。将
*存储打印到日志中,查看谁是罪魁祸首。@EgorSkriptunoff!!!我不初始化内存!!!因为它不是空的,所以会被取消引用!让我们看看把那个该死的值归零是否有帮助。谢谢你的指点@fsfod我坐在c37be68cf08上,上面有您提到的修复;但是好主意,谢谢!!