From: bert hubert Date: Mon, 26 Oct 2015 13:53:09 +0000 (+0100) Subject: fix leaving table on the lua stack while waiting for answers X-Git-Tag: dnsdist-1.0.0-alpha1~262^2~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=59d40d8459531a98ddc48f1cd852d12cbfd2d566;p=pdns fix leaving table on the lua stack while waiting for answers --- diff --git a/pdns/lua-pdns.cc b/pdns/lua-pdns.cc index ae59864bd..18e955260 100644 --- a/pdns/lua-pdns.cc +++ b/pdns/lua-pdns.cc @@ -85,6 +85,46 @@ static bool getFromTable(lua_State *lua, const std::string &key, uint32_t& value } +void pushLuaTable(lua_State* lua, const vector>& table) +{ + lua_newtable(lua); + int pos=0; + for(const auto& e : table) { + lua_pushstring(lua, e.second.c_str()); + lua_setfield(lua, -2, e.first.c_str()); + } +} + +vector> getLuaTable(lua_State* lua, int index) +{ + vector> ret; + // Push another reference to the table on top of the stack (so we know + // where it is, and this function can work for negative, positive and + // pseudo indices + lua_pushvalue(lua, index); + // stack now contains: -1 => table + lua_pushnil(lua); + // stack now contains: -1 => nil; -2 => table + while (lua_next(lua, -2)) { + // stack now contains: -1 => value; -2 => key; -3 => table + // copy the key so that lua_tostring does not modify the original + lua_pushvalue(lua, -2); + // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table + const char *key = lua_tostring(lua, -1); + const char *value = lua_tostring(lua, -2); + ret.push_back({key,value}); + // pop value + copy of key, leaving original key + lua_pop(lua, 2); + // stack now contains: -1 => key; -2 => table + } + // stack now contains: -1 => table (when lua_next returns 0 it pops the key + // but does not push anything.) + // Pop table + lua_pop(lua, 1); + // Stack is now the same as it was on entry to this function + return ret; +} + void pushResourceRecordsTable(lua_State* lua, const vector& records) { diff --git a/pdns/lua-pdns.hh b/pdns/lua-pdns.hh index 07e394bc2..0b71b1826 100644 --- a/pdns/lua-pdns.hh +++ b/pdns/lua-pdns.hh @@ -37,6 +37,8 @@ void pushResourceRecordsTable(lua_State* lua, const vector& records); void popResourceRecordsTable(lua_State *lua, const DNSName &query, vector& ret); void pushSyslogSecurityLevelTable(lua_State *lua); int getLuaTableLength(lua_State* lua, int depth); +std::vector> getLuaTable(lua_State* lua, int index=0); +void pushLuaTable(lua_State* lua, const vector>& table); void luaStackDump (lua_State *lua); extern "C" int luaopen_iputils(lua_State*); #endif diff --git a/pdns/lua-recursor.cc b/pdns/lua-recursor.cc index 09cbd9f6c..2726f4053 100644 --- a/pdns/lua-recursor.cc +++ b/pdns/lua-recursor.cc @@ -288,9 +288,8 @@ bool RecursorLua::passthrough(const string& func, const ComboAddress& remote, co string callback; getFromTable("callback", callback); - lua_remove(d_lua, -2); - - // XXX THIS IS PLAIN WRONG - WE LEAVE STUFF ON THE LUA STACK AND EXPECT IT TO STILL BE HERE WHEN WE GET BACK! + auto table = getLuaTable(d_lua, -1); + lua_pop(d_lua, 2); string answer = GenUDPQueryResponse(ComboAddress(dest), uquery); lua_getglobal(d_lua, callback.c_str()); @@ -298,12 +297,8 @@ bool RecursorLua::passthrough(const string& func, const ComboAddress& remote, co lua_pushstring(d_lua, remote.toString().c_str() ); lua_pushstring(d_lua, query.toString().c_str() ); lua_pushnumber(d_lua, qtype.getCode() ); - - lua_pushvalue(d_lua, -5); - lua_remove(d_lua, -6); - - lua_pushstring(d_lua, answer.c_str()); - lua_setfield(d_lua, -2, "response"); + table.push_back({"response", answer}); + pushLuaTable(d_lua, table); if(lua_pcall(d_lua, 4, 3, 0)) { // NOTE! Means we always get 3 stack entries back, no matter what our lua hook returned! string error=string("lua error in '"+func+"' while callback for '"+query.toString()+"|"+qtype.getName()+": ")+lua_tostring(d_lua, -1);