From 4134a8a90f2fea8c9e09365919ac922badbfa14d Mon Sep 17 00:00:00 2001 From: dkf Date: Sat, 24 Nov 2007 12:57:53 +0000 Subject: Fix stack corruption in [dict append] compiler --- ChangeLog | 32 ++++++++++++++++------------- generic/tclCompCmds.c | 57 ++++++++++++++++++++++++++++----------------------- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/ChangeLog b/ChangeLog index ea34251..fd4e879 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,19 +1,23 @@ +2007-11-24 Donal K. Fellows + + * generic/tclCompCmds.c (TclCompileDictAppendCmd): Fix bug in [dict + append] compiler which caused strange stack corruption. + 2007-11-23 Andreas Kupries - * generic/tclIORChan.c: Fixed a problem with reflected - channels. 'chan postevent' is defined to work only from within - the interpreter containing the handler command. Sensible, we - want only handler commands to use it. It identifies the channel - by handle. The channel moves to a different interpreter or - thread. The interpreter containing the handler command doesn't - know the channel any longer. 'chan postevent' fails, not finding - the channel any longer. Uhm. - - Fixed by creating a second per-interpreter channel table, just - for reflected channels, where each interpreter remembers for - which reflected channels it has the handler command. This info - does not move with the channel itself. The table is updated by - 'chan create', and used by 'chan postevent'. + * generic/tclIORChan.c: Fixed a problem with reflected channels. 'chan + postevent' is defined to work only from within the interpreter + containing the handler command. Sensible, we want only handler + commands to use it. It identifies the channel by handle. The channel + moves to a different interpreter or thread. The interpreter containing + the handler command doesn't know the channel any longer. 'chan + postevent' fails, not finding the channel any longer. Uhm. + + Fixed by creating a second per-interpreter channel table, just for + reflected channels, where each interpreter remembers for which + reflected channels it has the handler command. This info does not move + with the channel itself. The table is updated by 'chan create', and + used by 'chan postevent'. * tests/ioCmd.test: Updated the testsuite. diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 92accfc..0c603c5 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompCmds.c,v 1.131 2007/11/23 15:00:24 dkf Exp $ + * RCS: @(#) $Id: tclCompCmds.c,v 1.132 2007/11/24 12:57:56 dkf Exp $ */ #include "tclInt.h" @@ -1174,49 +1174,54 @@ TclCompileDictAppendCmd( { Proc *procPtr = envPtr->procPtr; DefineLineInformation; /* TIP #280 */ - Tcl_Token *tokenPtr, *varTokenPtr; - int numWords, i, dictVarIndex, nameChars; - const char *name; + Tcl_Token *tokenPtr; + int i, dictVarIndex; /* - * There must be at least two argument after the command. + * There must be at least two argument after the command. And we impose an + * (arbirary) safe limit; anyone exceeding it should stop worrying about + * speed quite so much. ;-) */ - if (parsePtr->numWords < 3) { + if (parsePtr->numWords<4 || parsePtr->numWords>100 || procPtr==NULL) { return TCL_ERROR; } - tokenPtr = TokenAfter(parsePtr->tokenPtr); - numWords = parsePtr->numWords-1; /* - * Arbirary safe limit; anyone exceeding it should stop worrying about - * speed quite so much. ;-) + * Get the index of the local variable that we will be working with. */ - if (parsePtr->numWords > 100 || procPtr == NULL) { + tokenPtr = TokenAfter(parsePtr->tokenPtr); + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { return TCL_ERROR; - } + } else { + register const char *name = tokenPtr[1].start; + register int nameChars = tokenPtr[1].size; - varTokenPtr = TokenAfter(tokenPtr); - if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { - return TCL_ERROR; - } - name = varTokenPtr[1].start; - nameChars = varTokenPtr[1].size; - if (!TclIsLocalScalar(name, nameChars)) { - return TCL_ERROR; + if (!TclIsLocalScalar(name, nameChars)) { + return TCL_ERROR; + } + dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr); } - dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, procPtr); - tokenPtr = TokenAfter(varTokenPtr); - for (i=1 ; inumWords-1 ; i++) { + /* + * Produce the string to concatenate onto the dictionary entry. + */ + + tokenPtr = TokenAfter(tokenPtr); + for (i=2 ; inumWords ; i++) { CompileWord(envPtr, tokenPtr, interp, i); tokenPtr = TokenAfter(tokenPtr); } - if (parsePtr->numWords > 3) { - TclEmitInstInt1( INST_CONCAT1, parsePtr->numWords-2, envPtr); + if (parsePtr->numWords > 4) { + TclEmitInstInt1(INST_CONCAT1, parsePtr->numWords-2, envPtr); } - TclEmitInstInt4( INST_DICT_APPEND, dictVarIndex, envPtr); + + /* + * Do the concatenation. + */ + + TclEmitInstInt4(INST_DICT_APPEND, dictVarIndex, envPtr); return TCL_OK; } -- cgit v0.12