summaryrefslogtreecommitdiffstats
path: root/generic/tclStringObj.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2017-06-16 20:28:53 (GMT)
committerdgp <dgp@users.sourceforge.net>2017-06-16 20:28:53 (GMT)
commitd9c2af2b87253036592e42ee6450a8e735ac2542 (patch)
treed761f4a3fb5546b8115125f8dc40389056c00bbf /generic/tclStringObj.c
parent8d9f1c9f4bfc7d76c34874feb574ff8c1e2becf0 (diff)
parentb4133af5ee0c655f627443f04d50f492eedc58fa (diff)
downloadtcl-d9c2af2b87253036592e42ee6450a8e735ac2542.zip
tcl-d9c2af2b87253036592e42ee6450a8e735ac2542.tar.gz
tcl-d9c2af2b87253036592e42ee6450a8e735ac2542.tar.bz2
merge trunk
Diffstat (limited to 'generic/tclStringObj.c')
-rw-r--r--generic/tclStringObj.c109
1 files changed, 88 insertions, 21 deletions
diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c
index d40c5e0..92cb137 100644
--- a/generic/tclStringObj.c
+++ b/generic/tclStringObj.c
@@ -2847,9 +2847,11 @@ TclStringCatObjv(
Tcl_Obj * const objv[],
Tcl_Obj **objPtrPtr)
{
- Tcl_Obj *objPtr, *objResultPtr, * const *ov;
- int oc, length = 0, binary = 1, first = 0, last = 0;
+ Tcl_Obj *objResultPtr, * const *ov;
+ int oc, length = 0, binary = 1;
int allowUniChar = 1, requestUniChar = 0;
+ int first = objc - 1; /* Index of first value possibly not empty */
+ int last = 0; /* Index of last value possibly not empty */
/* assert ( objc >= 0 ) */
@@ -2870,7 +2872,7 @@ TclStringCatObjv(
ov = objv, oc = objc;
do {
- objPtr = *ov++;
+ Tcl_Obj *objPtr = *ov++;
if (objPtr->bytes) {
/* Value has a string rep. */
@@ -2906,7 +2908,7 @@ TclStringCatObjv(
/* Result will be pure byte array. Pre-size it */
ov = objv; oc = objc;
do {
- objPtr = *ov++;
+ Tcl_Obj *objPtr = *ov++;
if (objPtr->bytes == NULL) {
int numBytes;
@@ -2916,10 +2918,10 @@ TclStringCatObjv(
last = objc - oc;
if (length == 0) {
first = last;
- }
- if ((length += numBytes) < 0) {
+ } else if (numBytes > INT_MAX - length) {
goto overflow;
}
+ length += numBytes;
}
}
} while (--oc);
@@ -2927,7 +2929,7 @@ TclStringCatObjv(
/* Result will be pure Tcl_UniChar array. Pre-size it. */
ov = objv; oc = objc;
do {
- objPtr = *ov++;
+ Tcl_Obj *objPtr = *ov++;
if ((objPtr->bytes == NULL) || (objPtr->length)) {
int numChars;
@@ -2937,10 +2939,10 @@ TclStringCatObjv(
last = objc - oc;
if (length == 0) {
first = last;
- }
- if ((length += numChars) < 0) {
+ } else if (numChars > INT_MAX - length) {
goto overflow;
}
+ length += numChars;
}
}
} while (--oc);
@@ -2948,26 +2950,91 @@ TclStringCatObjv(
/* Result will be concat of string reps. Pre-size it. */
ov = objv; oc = objc;
do {
+ Tcl_Obj *pendingPtr = NULL;
+
+ /*
+ * Loop until a possibly non-empty value is reached.
+ * Keep string rep generation pending when possible.
+ */
+
+ do {
+ /* assert ( pendingPtr == NULL ) */
+ /* assert ( length == 0 ) */
+
+ Tcl_Obj *objPtr = *ov++;
+
+ if (objPtr->bytes == NULL) {
+ /* No string rep; Take the chance we can avoid making it */
+ pendingPtr = objPtr;
+ } else {
+ Tcl_GetStringFromObj(objPtr, &length); /* PANIC? */
+ }
+ } while (--oc && (length == 0) && (pendingPtr == NULL));
+
+ /*
+ * Either we found a possibly non-empty value, and we
+ * remember this index as the first and last such value so
+ * far seen, or (oc == 0) and all values are known empty,
+ * so first = last = objc - 1 signals the right quick return.
+ */
+
+ first = last = objc - oc - 1;
+
+ if (oc && (length == 0)) {
+ int numBytes;
+
+ /* assert ( pendingPtr != NULL ) */
+
+ /*
+ * There's a pending value followed by more values.
+ * Loop over remaining values generating strings until
+ * a non-empty value is found, or the pending value gets
+ * its string generated.
+ */
+
+ do {
+ Tcl_Obj *objPtr = *ov++;
+ Tcl_GetStringFromObj(objPtr, &numBytes); /* PANIC? */
+ } while (--oc && numBytes == 0 && pendingPtr->bytes == NULL);
+
+ if (numBytes) {
+ last = objc -oc -1;
+ }
+ if (oc || numBytes) {
+ Tcl_GetStringFromObj(pendingPtr, &length);
+ }
+ if (length == 0) {
+ if (numBytes) {
+ first = last;
+ }
+ } else if (numBytes > INT_MAX - length) {
+ goto overflow;
+ }
+ length += numBytes;
+ }
+ } while (oc && (length == 0));
+
+ while (oc) {
int numBytes;
+ Tcl_Obj *objPtr = *ov++;
- objPtr = *ov++;
+ /* assert ( length > 0 && pendingPtr == NULL ) */
- Tcl_GetStringFromObj(objPtr, &numBytes); /* PANIC? */
+ Tcl_GetStringFromObj(objPtr, &numBytes); /* PANIC? */
if (numBytes) {
last = objc - oc;
- if (length == 0) {
- first = last;
- }
- if ((length += numBytes) < 0) {
+ if (numBytes > INT_MAX - length) {
goto overflow;
}
+ length += numBytes;
}
- } while (--oc);
+ --oc;
+ }
}
- if (last == first /*|| length == 0 */) {
+ if (last <= first /*|| length == 0 */) {
/* Only one non-empty value or zero length; return first */
- /* NOTE: (length == 0) implies (last == first) */
+ /* NOTE: (length == 0) implies (last <= first) */
*objPtrPtr = objv[first];
return TCL_OK;
}
@@ -3073,9 +3140,9 @@ TclStringCatObjv(
return TCL_ERROR;
}
dst = Tcl_GetString(objResultPtr) + start;
- if (length > start) {
- TclFreeIntRep(objResultPtr);
- }
+
+ /* assert ( length > start ) */
+ TclFreeIntRep(objResultPtr);
} else {
objResultPtr = Tcl_NewObj(); /* PANIC? */
if (0 == Tcl_AttemptSetObjLength(objResultPtr, length)) {