summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2015-11-18 10:23:49 +0100
committerantirez <antirez@gmail.com>2015-11-18 10:23:49 +0100
commit4b0b28b4694067fef56d7bb9bd09efdaf02ca032 (patch)
tree637872761effc5dd16e6ffe7d7b5189e51cd33f1
parent1f35f2dd5ace63862ecd819c4d28f8d844720df1 (diff)
downloadredis-ldb.tar.gz
Lua debugger: infinite loop detection.ldb
-rw-r--r--src/scripting.c42
1 files changed, 35 insertions, 7 deletions
diff --git a/src/scripting.c b/src/scripting.c
index 63b78f4ca..060073e6c 100644
--- a/src/scripting.c
+++ b/src/scripting.c
@@ -1305,7 +1305,7 @@ void evalGenericCommand(client *c, int evalsha) {
lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
delhook = 1;
} else if (ldb.active) {
- lua_sethook(server.lua,luaLdbLineHook,LUA_MASKLINE,0);
+ lua_sethook(server.lua,luaLdbLineHook,LUA_MASKLINE|LUA_MASKCOUNT,100000);
delhook = 1;
}
@@ -2201,8 +2201,10 @@ void ldbMaxlen(sds *argv, int argc) {
}
}
-/* Read debugging commands from client. */
-void ldbRepl(lua_State *lua) {
+/* Read debugging commands from client.
+ * 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;
int argc;
@@ -2217,7 +2219,7 @@ void ldbRepl(lua_State *lua) {
* client is no longer connected. */
ldb.step = 0;
ldb.bpcount = 0;
- return;
+ return C_ERR;
}
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. */
sdsfreesplitres(argv,argc);
+ return C_OK;
}
/* 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) {
lua_getstack(lua,0,ar);
lua_getinfo(lua,"Sl",ar);
- if(strstr(ar->short_src,"user_script") == NULL) return;
-
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;
+
+ /* Check if a timeout occurred. */
+ 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) {
char *reason = "step over";
if (bp) reason = ldb.luabp ? "redis.breakpoint() called" :
"break point";
+ else if (timeout) reason = "timeout reached, infinite loop?";
ldb.step = 0;
ldb.luabp = 0;
ldbLog(sdscatprintf(sdsempty(),
@@ -2336,7 +2357,14 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
ldb.currentline, reason));
ldbLogSourceLine(ldb.currentline);
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();
}
}