Затирается указатель this после вызова lua_pcall с кастомным обработчиком ошибок
Есть класс-обертка для 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.
Ответы (1 шт):
Проблема оказалась в том, что при компиляции LuaJIT использовались измененные заголовочные файлы, а к проекту подключались файлы без изменений(забыли скопировать).
Суть изменений: расширить поле lua_Debug::short_src[](фиксированный массив char).
Для сравнения:
// структура при компиляции ПО
struct lua_Debug
{
// прочие поля
char short_src[60]; // <<<<
// прочие поля
int c_i;
}
// структура при компиляции LuaJIT как библиотеки
struct lua_Debug
{
// прочие поля
char short_src[600]; // <<<<
// прочие поля
int c_i;
}
То есть на стеке под структуру lua_Debug выделялось меньше памяти, чем нужно библиотеке, так как в программе использовались необноовленные заголовочные файлы.
Как следствие lua_getstack пишет данные в lua_Debug::c_i по смещению, заданному при компиляции библиотеки и затирает данные на стеке.