Lua注册表损坏,并将内容存储在0x3FF00000?
所以。这一个真是太棒了。我使用Lua注册表(akaLua注册表损坏,并将内容存储在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\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上,上面有您提到的修复;但是好主意,谢谢!!