2014-09-03 22 views
6

Sto sviluppando un programma che utilizza Lua per lo scripting e talvolta si blocca. Con GDB penso di aver trovato il problema, ma non so se lo ha risolto, poiché il segfault si sarebbe verificato solo sporadicamente. Così, il vecchio codice era questo:Lua: può causare un 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; 
     } 
    } 
} 

Il fatto è che questa funzione sarebbe chiamato un paio di volte al secondo, ma la funzione di cui ha bisogno per chiamare, non è sempre definito, così ho pensato che la pila sarebbe traboccare. Ho aggiunto la riga seguente:

lua_pop(L,lua_gettop(L)); 

E il segfault non si è più verificato. Questo potrebbe essere stato il problema?

risposta

5

L'utilizzo di lua_gettop(L) come argomento per lua_pop cancellerà l'intero stack API Lua (è equivalente a lua_settop(0)), che probabilmente non è quello che si desidera. Ma in effetti il ​​tuo problema è che lua_getglobal spinge sempre qualcosa; se non esiste alcun globale con il nome specificato, spinge nil, proprio come farebbe l'equivalente espressione di Lua. Tuttavia, lua_pcall apre la funzione e tutti gli argomenti (se ce ne sono, nel tuo caso hai specificato zero), quindi non avrai problemi se la funzione esiste. Quello che dovresti fare è aggiungere lua_pop(L, 1) ad una clausola else esterna if. In questo modo, la tua funzione sarà sempre bilanciata (ad esempio, lascia la pila com'era).

È possibile vedere queste cose nello Lua manual: per ogni funzione, è indicato nella descrizione e anche indicato in grigio, tra parentesi accanto al prototipo delle funzioni. Ad esempio, lua_getglobal ha [-0, +1, e], il che significa che non verrà inserito alcun elemento e (sempre) verrà premuto un elemento (e il significato è che potrebbe causare errori).

+1

Va notato che in Lua-> C la transizione lua garantisce di avere una pila nuova e in quel C-> lua la transizione lua assicura che lo stack sia ripulito da qualunque cosa tu abbia lasciato su di esso è necessario un bilanciamento in questi punti (potrebbe comunque essere una buona pratica). Finché si rimane in C, tuttavia, è richiesta la gestione dello stack (e il bilanciamento dello stack delle funzioni). –

1

Secondo lo www.lua.org/manual/5.2/manual.html#4.2, sei responsabile di mantenere pulito lo stack poiché Lua non eseguirà alcun controllo. Vorrei assumere che un segfault è un risultato ragionevole di non mantenere pulito lo stack (nuovi valori inseriti in una posizione di memoria al di fuori dello spazio effettivo dello stack e incidentalmente anche all'esterno della memoria virtuale dei processi).

Poiché non si chiama lua_pcall per rimuovere la non funzione dallo stack, questo aumenterebbe la pila indefinitamente.

La soluzione dovrebbe funzionare, a meno che la funzione chiamata non lasci qualcosa in pila. Poiché si imposta nresults su 0, Lua non lascia alcun risultato sullo stack.

La mia comprensione del riferimento lua_pcall è, tuttavia, che i codici di errore possono essere lasciati nello stack anche se nresults è 0. Edit: Ho anche controllato questo comportamento ed è esattamente come pensavo che fosse.

In questo caso chiamare lua_gettop all'inizio e lua_settop alla fine funzionerebbe in ogni caso e manterrebbe il tuo stack bilanciato.

Problemi correlati