diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2013-02-04 14:40:40 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2013-02-04 14:40:40 (GMT) |
commit | 5537ab67eb915869ddd76bfbe1a7881c6faca15a (patch) | |
tree | 9f69275332c80280626c60becf9e973a7d69c4da /generic | |
parent | 586e53a4ac38b4a017a8be29a3832632ef62705a (diff) | |
parent | 5e82c1c3bc9f6e0222ba44ec737ef82ea07d6e5e (diff) | |
download | tcl-5537ab67eb915869ddd76bfbe1a7881c6faca15a.zip tcl-5537ab67eb915869ddd76bfbe1a7881c6faca15a.tar.gz tcl-5537ab67eb915869ddd76bfbe1a7881c6faca15a.tar.bz2 |
[3603163]: Stop crash in weird case where [eval] is used to make [array set]
get confused about whether there is a local variable table or not. Thanks to
Poor Yorick for identifying a reproducible crashing case.
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclCompCmds.c | 41 |
1 files changed, 23 insertions, 18 deletions
diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 389c1ee..4751455 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -284,7 +284,7 @@ TclCompileArraySetCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { DefineLineInformation; /* TIP #280 */ - Tcl_Token *tokenPtr; + Tcl_Token *varTokenPtr, *dataTokenPtr; int simpleVarName, isScalar, localIndex; int dataVar, iterVar, keyVar, valVar, infoIndex; int back, fwd, offsetBack, offsetFwd, savedStackDepth; @@ -294,10 +294,10 @@ TclCompileArraySetCmd( return TCL_ERROR; } - tokenPtr = TokenAfter(parsePtr->tokenPtr); - PushVarNameWord(interp, tokenPtr, envPtr, TCL_NO_ELEMENT, + varTokenPtr = TokenAfter(parsePtr->tokenPtr); + PushVarNameWord(interp, varTokenPtr, envPtr, TCL_NO_ELEMENT, &localIndex, &simpleVarName, &isScalar, 1); - tokenPtr = TokenAfter(tokenPtr); + dataTokenPtr = TokenAfter(varTokenPtr); if (!isScalar) { return TCL_ERROR; } @@ -307,7 +307,8 @@ TclCompileArraySetCmd( * operation. */ - if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD && tokenPtr[1].size == 0) { + if (dataTokenPtr->type == TCL_TOKEN_SIMPLE_WORD + && dataTokenPtr[1].size == 0) { if (localIndex >= 0) { TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr); TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr); @@ -326,7 +327,16 @@ TclCompileArraySetCmd( return TCL_OK; } - if (envPtr->procPtr == NULL) { + /* + * Prepare for the internal foreach. + */ + + dataVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); + iterVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); + keyVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); + valVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); + + if (dataVar < 0) { /* * Right number of arguments, but not compilable as we can't allocate * (unnamed) local variables to manage the internal iteration. @@ -343,21 +353,16 @@ TclCompileArraySetCmd( cmdPtr); TclEmitPush(cmdLit, envPtr); TclDecrRefCount(objPtr); - TclEmitInstInt4(INST_REVERSE, 2, envPtr); - CompileWord(envPtr, tokenPtr, interp, 2); + if (localIndex >= 0) { + CompileWord(envPtr, varTokenPtr, interp, 1); + } else { + TclEmitInstInt4(INST_REVERSE, 2, envPtr); + } + CompileWord(envPtr, dataTokenPtr, interp, 2); TclEmitInstInt1(INST_INVOKE_STK1, 3, envPtr); return TCL_OK; } - /* - * Prepare for the internal foreach. - */ - - dataVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); - iterVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); - keyVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); - valVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); - infoPtr = ckalloc(sizeof(ForeachInfo) + sizeof(ForeachVarList *)); infoPtr->numLists = 1; infoPtr->firstValueTemp = dataVar; @@ -372,7 +377,7 @@ TclCompileArraySetCmd( * Start issuing instructions to write to the array. */ - CompileWord(envPtr, tokenPtr, interp, 2); + CompileWord(envPtr, dataTokenPtr, interp, 2); TclEmitOpcode( INST_DUP, envPtr); TclEmitOpcode( INST_LIST_LENGTH, envPtr); PushLiteral(envPtr, "1", 1); |