summaryrefslogtreecommitdiffstats
path: root/generic/tclListObj.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2011-03-03 21:07:17 (GMT)
committerdgp <dgp@users.sourceforge.net>2011-03-03 21:07:17 (GMT)
commit3369c9129fa90ad0a083438bb7b066a1df3ee8d6 (patch)
tree94c6ec6f45a829d8ef54b008b42fda71118c1b35 /generic/tclListObj.c
parente729c2775a2779c6a58e56fd171dbee06bcc53d9 (diff)
downloadtcl-3369c9129fa90ad0a083438bb7b066a1df3ee8d6.zip
tcl-3369c9129fa90ad0a083438bb7b066a1df3ee8d6.tar.gz
tcl-3369c9129fa90ad0a083438bb7b066a1df3ee8d6.tar.bz2
Significant rewrite of the Tcl*(Scan|Convert)*Element() system, and revisions
to the callers. Needs more work on comments, and testing to check for any performance impact in either direction. Fixes reported bug.
Diffstat (limited to 'generic/tclListObj.c')
-rw-r--r--generic/tclListObj.c67
1 files changed, 33 insertions, 34 deletions
diff --git a/generic/tclListObj.c b/generic/tclListObj.c
index b2a951e..3c48a2f 100644
--- a/generic/tclListObj.c
+++ b/generic/tclListObj.c
@@ -1842,74 +1842,73 @@ UpdateStringOfList(
Tcl_Obj *listPtr) /* List object with string rep to update. */
{
# define LOCAL_SIZE 20
- int localFlags[LOCAL_SIZE], *flagPtr;
+ int localFlags[LOCAL_SIZE], *flagPtr = NULL;
List *listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
int numElems = listRepPtr->elemCount;
- register int i;
+ int i, length, bytesNeeded = 0;
char *elem, *dst;
- int length;
Tcl_Obj **elemPtrs;
+ const int maxFlags = UINT_MAX / sizeof(int);
/*
- * Convert each element of the list to string form and then convert it to
- * proper list element form, adding it to the result buffer.
+ * Mark the list as being canonical; although it will now have a string
+ * rep, it is one we derived through proper "canonical" quoting and so
+ * it's known to be free from nasties relating to [concat] and [eval].
*/
+ listRepPtr->canonicalFlag = 1;
+
+ /* Handle empty list case first, so rest of the routine is simpler */
+
+ if (numElems == 0) {
+ listPtr->bytes = tclEmptyStringRep;
+ listPtr->length = 0;
+ return;
+ }
+
/*
* Pass 1: estimate space, gather flags.
*/
if (numElems <= LOCAL_SIZE) {
flagPtr = localFlags;
+ } else if (numElems > maxFlags) {
+ Tcl_Panic("UpdateStringOfList: size requirement exceeds limits");
} else {
flagPtr = (int *) ckalloc((unsigned) numElems * sizeof(int));
}
- listPtr->length = 1;
elemPtrs = &listRepPtr->elements;
for (i = 0; i < numElems; i++) {
+ flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 );
elem = TclGetStringFromObj(elemPtrs[i], &length);
- listPtr->length += Tcl_ScanCountedElement(elem, length, flagPtr+i)+1;
-
- /*
- * Check for continued sanity. [Bug 1267380]
- */
-
- if (listPtr->length < 1) {
- Tcl_Panic("string representation size exceeds sane bounds");
+ bytesNeeded += TclScanElement(elem, length, flagPtr+i);
+ if (bytesNeeded < 0) {
+ Tcl_Panic("UpdateStringOfList: size requirement exceeds limits");
}
}
+ if (bytesNeeded > INT_MAX - numElems + 1) {
+ Tcl_Panic("UpdateStringOfList: size requirement exceeds limits");
+ }
+ bytesNeeded += numElems;
/*
* Pass 2: copy into string rep buffer.
*/
- listPtr->bytes = ckalloc((unsigned) listPtr->length);
+ listPtr->length = bytesNeeded - 1;
+ listPtr->bytes = ckalloc((unsigned) bytesNeeded);
dst = listPtr->bytes;
for (i = 0; i < numElems; i++) {
+ flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 );
elem = TclGetStringFromObj(elemPtrs[i], &length);
- dst += Tcl_ConvertCountedElement(elem, length, dst,
- flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH));
- *dst = ' ';
- dst++;
+ dst += TclConvertElement(elem, length, dst, flagPtr[i]);
+ *dst++ = ' ';
}
+ listPtr->bytes[listPtr->length] = '\0';
+
if (flagPtr != localFlags) {
ckfree((char *) flagPtr);
}
- if (dst == listPtr->bytes) {
- *dst = 0;
- } else {
- dst--;
- *dst = 0;
- }
- listPtr->length = dst - listPtr->bytes;
-
- /*
- * Mark the list as being canonical; although it has a string rep, it is
- * one we derived through proper "canonical" quoting and so it's known to
- * be free from nasties relating to [concat] and [eval].
- */
-
- listRepPtr->canonicalFlag = 1;
}
/*