Skip to content

Commit

Permalink
Prevent infinite recursion for eval, alias
Browse files Browse the repository at this point in the history
Signed-off-by: Steve Bennett <steveb@workware.net.au>
  • Loading branch information
msteveb committed Dec 2, 2011
1 parent 666f15f commit ddfbf9f
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 37 deletions.
71 changes: 36 additions & 35 deletions jim.c
Original file line number Diff line number Diff line change
Expand Up @@ -5051,7 +5051,8 @@ Jim_Interp *Jim_CreateInterp(void)

memset(i, 0, sizeof(*i));

i->maxNestingDepth = JIM_MAX_NESTING_DEPTH;
i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH;
i->maxEvalDepth = JIM_MAX_EVAL_DEPTH;
i->lastCollectTime = time(NULL);

/* Note that we can create objects only after the
Expand Down Expand Up @@ -9676,6 +9677,35 @@ static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv, Jim_Ob
return retCode;
}

static int JimInvokeCommand(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *fileNameObj, int linenr, int objc, Jim_Obj *const *objv)
{
int retcode;

if (cmdPtr == NULL) {
return JimUnknown(interp, objc, objv, fileNameObj, linenr);
}
if (interp->evalDepth == interp->maxEvalDepth) {
Jim_SetResultString(interp, "Infinite eval recursion", -1);
return JIM_ERR;
}
interp->evalDepth++;

/* Call it -- Make sure result is an empty object. */
JimIncrCmdRefCount(cmdPtr);
Jim_SetEmptyResult(interp);
if (cmdPtr->isproc) {
retcode = JimCallProcedure(interp, cmdPtr, fileNameObj, linenr, objc, objv);
}
else {
interp->cmdPrivData = cmdPtr->u.native.privData;
retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
}
JimDecrCmdRefCount(interp, cmdPtr);
interp->evalDepth--;

return retcode;
}

/* Eval the object vector 'objv' composed of 'objc' elements.
* Every element is used as single argument.
* Jim_EvalObj() will call this function every time its object
Expand All @@ -9694,24 +9724,11 @@ static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv,
/* Incr refcount of arguments. */
for (i = 0; i < objc; i++)
Jim_IncrRefCount(objv[i]);

/* Command lookup */
cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
if (cmdPtr == NULL) {
retcode = JimUnknown(interp, objc, objv, fileNameObj, linenr);
}
else {
/* Call it -- Make sure result is an empty object. */
JimIncrCmdRefCount(cmdPtr);
Jim_SetEmptyResult(interp);
if (cmdPtr->isproc) {
retcode = JimCallProcedure(interp, cmdPtr, fileNameObj, linenr, objc, objv);
}
else {
interp->cmdPrivData = cmdPtr->u.native.privData;
retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
}
JimDecrCmdRefCount(interp, cmdPtr);
}
retcode = JimInvokeCommand(interp, cmdPtr, fileNameObj, linenr, objc, objv);

/* Decr refcount of arguments and return the retcode */
for (i = 0; i < objc; i++)
Jim_DecrRefCount(interp, objv[i]);
Expand Down Expand Up @@ -10131,23 +10148,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
if (retcode == JIM_OK && argc) {
/* Lookup the command to call */
cmd = Jim_GetCommand(interp, argv[0], JIM_ERRMSG);
if (cmd != NULL) {
/* Call it -- Make sure result is an empty object. */
JimIncrCmdRefCount(cmd);
Jim_SetEmptyResult(interp);
if (cmd->isproc) {
retcode =
JimCallProcedure(interp, cmd, script->fileNameObj, linenr, argc, argv);
} else {
interp->cmdPrivData = cmd->u.native.privData;
retcode = cmd->u.native.cmdProc(interp, argc, argv);
}
JimDecrCmdRefCount(interp, cmd);
}
else {
/* Call [unknown] */
retcode = JimUnknown(interp, argc, argv, script->fileNameObj, linenr);
}
retcode = JimInvokeCommand(interp, cmd, script->fileNameObj, linenr, argc, argv);
if (interp->signal_level && interp->sigmask) {
/* Check for a signal after each command */
retcode = JIM_SIGNAL;
Expand Down Expand Up @@ -10274,7 +10275,7 @@ static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameO
}

/* Check if there are too nested calls */
if (interp->framePtr->level == interp->maxNestingDepth) {
if (interp->framePtr->level == interp->maxCallFrameDepth) {
Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
return JIM_ERR;
}
Expand Down
7 changes: 5 additions & 2 deletions jim.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ extern "C" {
/* The following are internal codes and should never been seen/used */
#define JIM_EVAL 7

#define JIM_MAX_NESTING_DEPTH 1000 /* default max nesting depth */
#define JIM_MAX_CALLFRAME_DEPTH 1000 /* default max nesting depth for procs */
#define JIM_MAX_EVAL_DEPTH 2000 /* default max nesting depth for eval */

/* Some function get an integer argument with flags to change
* the behaviour. */
Expand Down Expand Up @@ -517,7 +518,9 @@ typedef struct Jim_Interp {
int errorLine; /* Error line where an error occurred. */
Jim_Obj *errorFileNameObj; /* Error file where an error occurred. */
int addStackTrace; /* > 0 If a level should be added to the stack trace */
int maxNestingDepth; /* Used for infinite loop detection. */
int maxCallFrameDepth; /* Used for infinite loop detection. */
int maxEvalDepth; /* Used for infinite loop detection. */
int evalDepth; /* Current eval depth */
int returnCode; /* Completion code to return on JIM_RETURN. */
int returnLevel; /* Current level of 'return -level' */
int exitCode; /* Code to return to the OS on JIM_EXIT. */
Expand Down
18 changes: 18 additions & 0 deletions regtest.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,24 @@ catch {
incr globx
puts "TEST 25 PASSED"

# REGTEST 26
# 2 Dec 2011 - infinite eval recursion
catch {
set x 0
set y {incr x; eval $y}
eval $y
} msg
puts "TEST 26 PASSED"

# REGTEST 27
# 2 Dec 2011 - infinite alias recursion
catch {
proc p {} {}
alias p p
p
} msg
puts "TEST 27 PASSED"

# TAKE THE FOLLOWING puts AS LAST LINE

puts "--- ALL TESTS PASSED ---"

0 comments on commit ddfbf9f

Please sign in to comment.