summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorapnadkarni <apnmbx-wits@yahoo.com>2023-04-27 12:47:08 (GMT)
committerapnadkarni <apnmbx-wits@yahoo.com>2023-04-27 12:47:08 (GMT)
commit18f61eeeeb444689bb9871ce53c8187e7bc3133a (patch)
tree8027a8be65cf65dbf63921e51113b8fcca7590c5
parent5ddcd8fea990af78cce1ef7d706e0a0ce81a317b (diff)
downloadtcl-18f61eeeeb444689bb9871ce53c8187e7bc3133a.zip
tcl-18f61eeeeb444689bb9871ce53c8187e7bc3133a.tar.gz
tcl-18f61eeeeb444689bb9871ce53c8187e7bc3133a.tar.bz2
More checks for exceeding max words
-rw-r--r--generic/tclBasic.c28
-rw-r--r--generic/tclExecute.c10
-rw-r--r--generic/tclInt.h6
-rw-r--r--generic/tclParse.c15
-rw-r--r--generic/tclUtil.c40
-rw-r--r--tests/bigdata.test22
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