summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorapnadkarni <apnmbx-wits@yahoo.com>2023-04-29 03:15:11 (GMT)
committerapnadkarni <apnmbx-wits@yahoo.com>2023-04-29 03:15:11 (GMT)
commit85a2a9172920e13d3a1aa6ff861073ad690ccb12 (patch)
treea36d9351e7580de003fd8b57e031bdfedce03de8
parenta6d654980e6e0e35e1cb74dc978f654c216ce7e4 (diff)
parent175931c905a640bfd9ee76f0896c142b8549e391 (diff)
downloadtcl-85a2a9172920e13d3a1aa6ff861073ad690ccb12.zip
tcl-85a2a9172920e13d3a1aa6ff861073ad690ccb12.tar.gz
tcl-85a2a9172920e13d3a1aa6ff861073ad690ccb12.tar.bz2
Fix [7cddd2845c] - crash with >= INT_MAX operands
-rw-r--r--generic/tclBasic.c28
-rw-r--r--generic/tclExecute.c12
-rw-r--r--generic/tclInt.h6
-rw-r--r--generic/tclParse.c15
-rw-r--r--generic/tclUtil.c40
-rw-r--r--tests/bigdata.test20
6 files changed, 97 insertions, 24 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 789c139..56c8207 100644
--- a/generic/tclExecute.c
+++ b/generic/tclExecute.c
@@ -981,10 +981,10 @@ GrowEvaluationStack(
{
ExecStack *esPtr = eePtr->execStackPtr, *oldPtr = NULL;
size_t newBytes;
- int growth = growth1;
- int newElems, currElems, needed = growth - (esPtr->endPtr - esPtr->tosPtr);
+ Tcl_Size growth = growth1;
+ Tcl_Size newElems, currElems, needed = growth - (esPtr->endPtr - esPtr->tosPtr);
Tcl_Obj **markerPtr = esPtr->markerPtr, **memStart;
- int moveWords = 0;
+ Tcl_Size moveWords = 0;
if (move) {
if (!markerPtr) {
@@ -2825,8 +2825,12 @@ TEBCresume(
pc += pcAdjustment;
TEBC_YIELD();
- return TclNREvalObjv(interp, objc, objv,
+ if (objc > INT_MAX) {
+ return TclCommandWordLimitError(interp, objc);
+ } else {
+ return TclNREvalObjv(interp, objc, objv,
TCL_EVAL_NOERR | TCL_EVAL_SOURCE_IN_FRAME, NULL);
+ }
case INST_INVOKE_REPLACE:
objc = TclGetUInt4AtPtr(pc+1);
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 a1ccd32..ccd34af 100644
--- a/tests/bigdata.test
+++ b/tests/bigdata.test
@@ -879,15 +879,25 @@ bigtest linsert-bigdata-1 "linsert" {4294967330 1} -body {
#
# list and {*}
-bigtestRO list-bigdata-1 {list {*} } {4294967296 0 4294967295} -body {
- unset -nocomplain l2
+# TODO - compiled and uncompiled behave differently so tested separately
+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]
-} -setup {
- set l [bigList 0x100000000]
} -cleanup {
bigClean
-} -constraints bug-7cddd2845c
+} -constraints {
+ bigdata
+} -result {4294967296 0 5}
+test list-bigdata-1.uncompiled {list {*}} -body {
+ set l [bigList 0x7fffffff]
+ testevalex {set l2 [list {*}$l]}
+} -cleanup {
+ bigClean
+} -constraints {
+ bigdata
+} -result {Number of words in command exceeds limit 2147483647.} -returnCodes error
#
# llength