Lua API 有一个包装类:
class Lua
{
public /* lua api */:
//....
private /* members */:
lua_State* lua;
//....
};
我需要在脚本中扩展有关错误的信息:在错误发生时添加 StackTrace 和变量值。
好的,我正在添加视图功能
static int add_stack_trace(lua_State* lua)
{
std::ostringstream msg;
lua_Debug record;
msg << std::endl
<< lua_tostring(lua, -1) // original error message
<< std::endl;
for (int level = 0; lua_getstack(lua, level, &record); level++)
{
lua_getinfo(lua, "Snlu", record);
msg << " [" << record.what << "]"
<< " line" << std::setw(6) << record.currentline << " : " << record.short_src // error position
<< " it function '" << (record.name ? record.name : "{no name}") << "'" // function name
<< " lines " << record.linedefined << " .. " << record.lastlinedefined // function lines
<< std::endl;
}
auto result = msg.str();
lua_pushlstring(lua, result.c_str(), result.size());
return 1;
}
为:制作包装器lua_pcall
:
int Lua::pcall(int numArgs, int numResults)
{
lua_pushcfunction(lua, &Lua::add_stack_trace);
lua_insert(lua, 1);
auto code = ::lua_pcall(lua, numArgs, numResults, 1); // use add_stack_trace as error handler
lua_remove(lua, 1);
return code;
}
然后“乐趣”开始了:
当使用自定义处理程序并且脚本中出现错误时,应用程序开始崩溃并出现内存访问错误。
重现错误的最小处理程序代码:
int handler(lua_State* lua)
{
lua_Debug record{};
for (int level = 0; lua_getstack(lua, level, &record); level++)
{
}
return 1;
}
通过调试器判断,在调用期间,值(地址本身)lua_pcall + handler
以某种方式被覆盖this
实际上问题是:为什么会发生这种情况以及如何克服它?
附加信息:
- 该问题仅在
Release
- 装配为
x64
Visual Studio 2017
和使用的编译器LuaJIT-2.0.x
。
问题原来是
LuaJIT
在编译过程中使用了修改后的头文件,并且文件没有更改就连接到项目(他们忘记复制它们)。变化的本质:扩展字段
lua_Debug::short_src[]
(固定数组char
)。为了比较:
也就是说,在堆栈上为结构分配的内存
lua_Debug
少于库所需的内存,因为程序使用了未更新的头文件。结果
lua_getstack
,将数据写lua_Debug::c_i
入库编译时指定的偏移量,并覆盖堆栈上的数据。