Lua debugger: infinite loop detection.

This commit is contained in:
antirez 2015-11-18 10:23:49 +01:00
parent 1f35f2dd5a
commit 4b0b28b469

View File

@ -1305,7 +1305,7 @@ void evalGenericCommand(client *c, int evalsha) {
lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000); lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
delhook = 1; delhook = 1;
} else if (ldb.active) { } else if (ldb.active) {
lua_sethook(server.lua,luaLdbLineHook,LUA_MASKLINE,0); lua_sethook(server.lua,luaLdbLineHook,LUA_MASKLINE|LUA_MASKCOUNT,100000);
delhook = 1; delhook = 1;
} }
@ -2201,8 +2201,10 @@ void ldbMaxlen(sds *argv, int argc) {
} }
} }
/* Read debugging commands from client. */ /* Read debugging commands from client.
void ldbRepl(lua_State *lua) { * Return C_OK if the debugging session is continuing, otherwise
* C_ERR if the client closed the connection or is timing out. */
int ldbRepl(lua_State *lua) {
sds *argv; sds *argv;
int argc; int argc;
@ -2217,7 +2219,7 @@ void ldbRepl(lua_State *lua) {
* client is no longer connected. */ * client is no longer connected. */
ldb.step = 0; ldb.step = 0;
ldb.bpcount = 0; ldb.bpcount = 0;
return; return C_ERR;
} }
ldb.cbuf = sdscatlen(ldb.cbuf,buf,nread); ldb.cbuf = sdscatlen(ldb.cbuf,buf,nread);
} }
@ -2314,6 +2316,7 @@ ldbLog(sdsnew(" in the next line of code."));
/* Free the current command argv if we break inside the while loop. */ /* Free the current command argv if we break inside the while loop. */
sdsfreesplitres(argv,argc); sdsfreesplitres(argv,argc);
return C_OK;
} }
/* This is the core of our Lua debugger, called each time Lua is about /* This is the core of our Lua debugger, called each time Lua is about
@ -2321,14 +2324,32 @@ ldbLog(sdsnew(" in the next line of code."));
void luaLdbLineHook(lua_State *lua, lua_Debug *ar) { void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
lua_getstack(lua,0,ar); lua_getstack(lua,0,ar);
lua_getinfo(lua,"Sl",ar); lua_getinfo(lua,"Sl",ar);
ldb.currentline = ar->currentline;
int bp = ldbIsBreakpoint(ldb.currentline) || ldb.luabp;
int timeout = 0;
/* Events outside our script are not interesting. */
if(strstr(ar->short_src,"user_script") == NULL) return; if(strstr(ar->short_src,"user_script") == NULL) return;
ldb.currentline = ar->currentline; /* Check if a timeout occurred. */
int bp = ldbIsBreakpoint(ldb.currentline) || ldb.luabp; if (ar->event == LUA_HOOKCOUNT && ldb.step == 0 && bp == 0) {
mstime_t elapsed = mstime() - server.lua_time_start;
mstime_t timelimit = server.lua_time_limit ?
server.lua_time_limit : 5000;
if (elapsed >= timelimit) {
timeout = 1;
ldb.step = 1;
} else {
return; /* No timeout, ignore the COUNT event. */
}
}
if (ldb.step || bp) { if (ldb.step || bp) {
char *reason = "step over"; char *reason = "step over";
if (bp) reason = ldb.luabp ? "redis.breakpoint() called" : if (bp) reason = ldb.luabp ? "redis.breakpoint() called" :
"break point"; "break point";
else if (timeout) reason = "timeout reached, infinite loop?";
ldb.step = 0; ldb.step = 0;
ldb.luabp = 0; ldb.luabp = 0;
ldbLog(sdscatprintf(sdsempty(), ldbLog(sdscatprintf(sdsempty(),
@ -2336,7 +2357,14 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
ldb.currentline, reason)); ldb.currentline, reason));
ldbLogSourceLine(ldb.currentline); ldbLogSourceLine(ldb.currentline);
ldbSendLogs(); ldbSendLogs();
ldbRepl(lua); if (ldbRepl(lua) == C_ERR && timeout) {
/* If the client closed the connection and we have a timeout
* connection, let's kill the script otherwise the process
* will remain blocked indefinitely. */
lua_pushstring(lua, "timeout during Lua debugging with client closing connection");
lua_error(lua);
}
server.lua_time_start = mstime();
} }
} }