2014-09-03 2 views
6

Я разрабатываю программу, которая использует Lua для написания сценариев, и иногда она будет разбиваться. С GDB я думаю, что нашел проблему, но я не знаю, разрешил ли она ее, поскольку segfault будет происходить только эпизодически. Таким образом, старый код был такой:Lua: Может ли это вызвать segfault?

void Call(std::string func){ 
    lua_getglobal(L, func.c_str()); //This is the line GDB mentioned in a backtrace 
    if(lua_isfunction(L,lua_gettop(L))) { 
     int err = lua_pcall(L, 0, 0,0); 
     if(err != 0){ 
      std::cout << "Lua error: " << luaL_checkstring(L, -1) << std::endl; 
     } 
    } 
} 

Дело в том, что эта функция будет называться несколько раз в секунду, но функция его нужно называть не всегда определяется, таким образом, я думал, что стек будет переполняться. Я добавил следующую строку:

lua_pop(L,lua_gettop(L)); 

И segfault больше не возникало. Может ли это быть проблемой?

ответ

5

Использование lua_gettop(L) в качестве аргумента для lua_pop очистит весь стек API Lua (это эквивалентно lua_settop(0)), что, вероятно, не то, что вы хотите. Но на самом деле ваша проблема в том, что lua_getglobal всегда что-то подталкивает; если глобальное имя с указанным именем не существует, оно толкает nil, как это делает эквивалентное выражение Lua. Однако lua_pcall выдает функцию и все аргументы (если они есть, в вашем случае вы указали нуль), поэтому вы не получите проблемы, если эта функция существует. Что вы должны сделать, это добавить lua_pop(L, 1) в статью else внешнего if. Таким образом, ваша функция всегда будет сбалансирована (т. Е. Оставить стек так, как было).

Вы можете увидеть эти вещи в Lua manual: для каждой функции это указано в описании, а также указано серым цветом в скобках рядом с прототипом функций. Например, lua_getglobal имеет [-0, +1, e], что означает, что он не будет выставлять никаких элементов и (всегда) нажимать один элемент (а также означает, что он может вызвать ошибки).

+1

Следует отметить, что при переходе Lua-> C lua гарантирует, что у вас есть новый стек, и на этом переходе C-> lua lua гарантирует, что стек очищен от того, что вы, возможно, оставили на нем, поэтому нет балансирование в этих точках требуется (однако, по-прежнему может быть хорошей практикой). Однако, пока вы находитесь на C, требуется управление стеком (и балансировка стека функций). –

1

Согласно www.lua.org/manual/5.2/manual.html#4.2, вы несете ответственность за сохранение стека, поскольку Lua не выполняет никаких проверок. Я хотел бы считать, что segfault является разумным результатом того, что вы не храните стек в чистоте (новые значения перемещаются в ячейку памяти за пределами фактического пространства стека и, случайно, также вне вашей виртуальной памяти процессов).

Поскольку вы не вызываете lua_pcall для удаления нефункции из стека, это увеличит стек на неопределенный срок.

Ваше решение должно работать, если вызываемая функция не оставляет что-то в стеке. Поскольку вы устанавливаете nresults на 0, Lua не оставляет никаких результатов в стеке.

Мое понимание ссылки lua_pcall заключается в том, что коды ошибок можно оставить в стеке, даже если nresults равен 0. Edit: Я также проверил это поведение, и это точно так, как я предполагал.

В этом случае вызов lua_gettop в начале и lua_settop в конце будет работать в любом случае и сбалансировать ваш стек.

Смежные вопросы