diff options
author | apnadkarni <apnmbx-wits@yahoo.com> | 2023-04-27 12:47:08 (GMT) |
---|---|---|
committer | apnadkarni <apnmbx-wits@yahoo.com> | 2023-04-27 12:47:08 (GMT) |
commit | 18f61eeeeb444689bb9871ce53c8187e7bc3133a (patch) | |
tree | 8027a8be65cf65dbf63921e51113b8fcca7590c5 | |
parent | 5ddcd8fea990af78cce1ef7d706e0a0ce81a317b (diff) | |
download | tcl-18f61eeeeb444689bb9871ce53c8187e7bc3133a.zip tcl-18f61eeeeb444689bb9871ce53c8187e7bc3133a.tar.gz tcl-18f61eeeeb444689bb9871ce53c8187e7bc3133a.tar.bz2 |
More checks for exceeding max words
-rw-r--r-- | generic/tclBasic.c | 28 | ||||
-rw-r--r-- | generic/tclExecute.c | 10 | ||||
-rw-r--r-- | generic/tclInt.h | 6 | ||||
-rw-r--r-- | generic/tclParse.c | 15 | ||||
-rw-r--r-- | generic/tclUtil.c | 40 | ||||
-rw-r--r-- | tests/bigdata.test | 22 |
6 files changed, 82 insertions, 39 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 480b72e..686cf62 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -5164,17 +5164,17 @@ TclEvalEx( { Interp *iPtr = (Interp *) interp; const char *p, *next; - const unsigned int minObjs = 20; + const int minObjs = 20; Tcl_Obj **objv, **objvSpace; int *expand, *lines, *lineSpace; Tcl_Token *tokenPtr; - int bytesLeft, expandRequested, code = TCL_OK; - Tcl_Size commandLength; + int expandRequested, code = TCL_OK; + Tcl_Size bytesLeft, commandLength; CallFrame *savedVarFramePtr;/* Saves old copy of iPtr->varFramePtr in case * TCL_EVAL_GLOBAL was set. */ int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS); int gotParse = 0; - TCL_HASH_TYPE i, objectsUsed = 0; + Tcl_Size i, objectsUsed = 0; /* These variables keep track of how much * state has been allocated while evaluating * the script, so that it can be freed @@ -5312,8 +5312,8 @@ TclEvalEx( Tcl_Size wordLine = line; const char *wordStart = parsePtr->commandStart; int *wordCLNext = clNext; - unsigned int objectsNeeded = 0; - unsigned int numWords = parsePtr->numWords; + Tcl_Size objectsNeeded = 0; + Tcl_Size numWords = parsePtr->numWords; /* * Generate an array of objects for the words of the command. @@ -5332,6 +5332,8 @@ TclEvalEx( for (objectsUsed = 0, tokenPtr = parsePtr->tokenPtr; objectsUsed < numWords; objectsUsed++, tokenPtr += tokenPtr->numComponents+1) { + Tcl_Size additionalObjsCount; + /* * TIP #280. Track lines to current word. Save the information * on a per-word basis, signaling dynamic words as needed. @@ -5381,11 +5383,21 @@ TclEvalEx( expandRequested = 1; expand[objectsUsed] = 1; - objectsNeeded += (numElements ? numElements : 1); + additionalObjsCount = (numElements ? numElements : 1); + } else { expand[objectsUsed] = 0; - objectsNeeded++; + additionalObjsCount = 1; + } + + /* Currently max command words in INT_MAX */ + if (additionalObjsCount > INT_MAX || + objectsNeeded > (INT_MAX - additionalObjsCount)) { + code = TclCommandWordLimitError(interp, -1); + Tcl_DecrRefCount(objv[objectsUsed]); + break; } + objectsNeeded += additionalObjsCount; if (wordCLNext) { TclContinuationsEnterDerived(objv[objectsUsed], diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 1e16d68..732cb87 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -2826,15 +2826,7 @@ TEBCresume( pc += pcAdjustment; TEBC_YIELD(); if (objc > INT_MAX) { - if (interp) { - Tcl_SetObjResult( - interp, - Tcl_ObjPrintf("Argument count %" TCL_SIZE_MODIFIER - "d exceeds limit %d.", - objc, - (int)INT_MAX)); - } - return TCL_ERROR; + return TclCommandWordLimitError(interp, objc); } else { return TclNREvalObjv(interp, objc, objv, TCL_EVAL_NOERR | TCL_EVAL_SOURCE_IN_FRAME, NULL); diff --git a/generic/tclInt.h b/generic/tclInt.h index d777e38..df708b4 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -4173,6 +4173,12 @@ MODULE_SCOPE int TclIndexEncode(Tcl_Interp *interp, Tcl_Obj *objPtr, MODULE_SCOPE Tcl_Size TclIndexDecode(int encoded, Tcl_Size endValue); MODULE_SCOPE int TclIndexInvalidError(Tcl_Interp *interp, const char *idxType, Tcl_Size idx); + +/* + * Error message utility functions + */ +MODULE_SCOPE int TclCommandWordLimitError(Tcl_Interp *interp, Tcl_Size count); + #endif /* TCL_MAJOR_VERSION > 8 */ /* Constants used in index value encoding routines. */ diff --git a/generic/tclParse.c b/generic/tclParse.c index 96f8a8e..d8b40e4 100644 --- a/generic/tclParse.c +++ b/generic/tclParse.c @@ -214,7 +214,7 @@ Tcl_ParseCommand( * command. */ char type; /* Result returned by CHAR_TYPE(*src). */ Tcl_Token *tokenPtr; /* Pointer to token being filled in. */ - int wordIndex; /* Index of word token for current word. */ + Tcl_Size wordIndex; /* Index of word token for current word. */ int terminators; /* CHAR_TYPE bits that indicate the end of a * command. */ const char *termPtr; /* Set by Tcl_ParseBraces/QuotedString to @@ -327,7 +327,7 @@ Tcl_ParseCommand( src = termPtr; numBytes = parsePtr->end - src; } else if (*src == '{') { - int expIdx = wordIndex + 1; + Tcl_Size expIdx = wordIndex + 1; Tcl_Token *expPtr; if (Tcl_ParseBraces(interp, src, numBytes, parsePtr, 1, @@ -345,7 +345,7 @@ Tcl_ParseCommand( expPtr = &parsePtr->tokenPtr[expIdx]; if ((0 == expandWord) /* Haven't seen prefix already */ - && (expIdx + 1 == (int)parsePtr->numTokens) + && (expIdx + 1 == parsePtr->numTokens) /* Only one token */ && (((1 == expPtr->size) /* Same length as prefix */ @@ -380,7 +380,7 @@ Tcl_ParseCommand( tokenPtr = &parsePtr->tokenPtr[wordIndex]; tokenPtr->size = src - tokenPtr->start; - tokenPtr->numComponents = (int)parsePtr->numTokens - (wordIndex + 1); + tokenPtr->numComponents = parsePtr->numTokens - (wordIndex + 1); if (expandWord) { Tcl_Size i; int isLiteral = 1; @@ -407,7 +407,8 @@ Tcl_ParseCommand( } if (isLiteral) { - int elemCount = 0, code = TCL_OK, literal = 1; + Tcl_Size elemCount = 0; + int code = TCL_OK, literal = 1; const char *nextElem, *listEnd, *elemStart; /* @@ -471,8 +472,8 @@ Tcl_ParseCommand( */ const char *listStart; - int growthNeeded = wordIndex + 2*elemCount - - (int)parsePtr->numTokens; + Tcl_Size growthNeeded = wordIndex + 2*elemCount + - parsePtr->numTokens; parsePtr->numWords += elemCount - 1; if (growthNeeded > 0) { diff --git a/generic/tclUtil.c b/generic/tclUtil.c index b765a0f..07b497b 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -3977,6 +3977,46 @@ TclIndexInvalidError ( } /* + *------------------------------------------------------------------------ + * + * TclCommandWordLimitErrpr -- + * + * Generates an error message limit on number of command words exceeded. + * + * Results: + * Always return TCL_ERROR. + * + * Side effects: + * If interp is not-NULL, an error message is stored in it. + * + *------------------------------------------------------------------------ + */ +int +TclCommandWordLimitError ( + Tcl_Interp *interp, /* May be NULL */ + Tcl_Size count) /* If <= 0, "unknown" */ +{ + if (interp) { + if (count > 0) { + Tcl_SetObjResult( + interp, + Tcl_ObjPrintf("Number of words (%" TCL_SIZE_MODIFIER + "d) in command exceeds limit %" TCL_SIZE_MODIFIER + "d.", + count, + (Tcl_Size)INT_MAX)); + } + else { + Tcl_SetObjResult(interp, + Tcl_ObjPrintf("Number of words in command exceeds " + "limit %" TCL_SIZE_MODIFIER "d.", + (Tcl_Size)INT_MAX)); + } + } + return TCL_ERROR; /* Always */ +} + +/* *---------------------------------------------------------------------- * * ClearHash -- diff --git a/tests/bigdata.test b/tests/bigdata.test index 87c5a59..d2749c0 100644 --- a/tests/bigdata.test +++ b/tests/bigdata.test @@ -880,32 +880,24 @@ bigtest linsert-bigdata-1 "linsert" {4294967330 1} -body { # # list and {*} # TODO - compiled and uncompiled behave differently so tested separately -bigtestRO xxlist-bigdata-1 {list {*} } {4294967296 0 4294967295} -body { - unset -nocomplain l2 - set l2 [list {*}$l] - list [llength $l2] [lindex $l2 0] [lindex $l2 end] -} -setup { - set l [bigList 0x100000000] -} -cleanup { - bigClean -} -constraints bug-7cddd2845c -test list-bigdata-1.compiled {list {*} } -body { +test list-bigdata-1.compiled {list {*}} -body { set l [bigList 0x100000000] set l2 [list {*}$l] unset l list [llength $l2] [lindex $l2 0] [lindex $l2 end] } -cleanup { bigClean +} -constraints { + bigdata } -result {4294967296 0 5} -test list-bigdata-1.uncompiled {list {*} } -body { +test list-bigdata-1.uncompiled {list {*}} -body { set l [bigList 0x7fffffff] testevalex {set l2 [list {*}$l]} - unset l - list [llength $l2] [lindex $l2 0] [lindex $l2 end] } -cleanup { bigClean -} -result {4294967296 0 5} - +} -constraints { + bigdata +} -result {Number of words in command exceeds limit 2147483647.} -returnCodes error # # llength |