diff options
-rw-r--r-- | generic/tclStringObj.c | 38 | ||||
-rw-r--r-- | tests/string.test | 30 |
2 files changed, 57 insertions, 11 deletions
diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c index aae52ba..aa99545 100644 --- a/generic/tclStringObj.c +++ b/generic/tclStringObj.c @@ -2916,10 +2916,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); @@ -2937,14 +2937,16 @@ 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); } else { + Tcl_Obj *pendingPtr = NULL; + /* Result will be concat of string reps. Pre-size it. */ ov = objv; oc = objc; do { @@ -2952,15 +2954,29 @@ TclStringCatObjv( objPtr = *ov++; - Tcl_GetStringFromObj(objPtr, &numBytes); /* PANIC? */ - if (numBytes) { + if ((length == 0) && (objPtr->bytes == NULL) && !pendingPtr) { + /* No string rep; Take the chance we can avoid making it */ + + last = objc - oc; + first = last; + pendingPtr = objPtr; + } else { + + Tcl_GetStringFromObj(objPtr, &numBytes); /* PANIC? */ + if (numBytes == 0) { + continue; + } last = objc - oc; + if (pendingPtr) { + Tcl_GetStringFromObj(pendingPtr, &length); /* PANIC? */ + pendingPtr = NULL; + } if (length == 0) { first = last; - } - if ((length += numBytes) < 0) { + } else if (numBytes > INT_MAX - length) { goto overflow; } + length += numBytes; } } while (--oc); } @@ -3073,9 +3089,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)) { diff --git a/tests/string.test b/tests/string.test index fa7f8fb..9c43f29 100644 --- a/tests/string.test +++ b/tests/string.test @@ -1994,6 +1994,36 @@ test string-29.4 {string cat, many args} { set r2 [string compare $xx [eval "string cat $vvs"]] list $r1 $r2 } {0 0} +test string-29.5 {string cat, efficiency} -body { + tcl::unsupported::representation [string cat [list x] [list]] +} -match glob -result {*no string representation} +test string-29.6 {string cat, efficiency} -body { + tcl::unsupported::representation [string cat [list] [list x]] +} -match glob -result {*no string representation} +test string-29.7 {string cat, efficiency} -body { + tcl::unsupported::representation [string cat [list x] [list] [list]] +} -match glob -result {*no string representation} +test string-29.8 {string cat, efficiency} -body { + tcl::unsupported::representation [string cat [list] [list x] [list]] +} -match glob -result {*no string representation} +test string-29.9 {string cat, efficiency} -body { + tcl::unsupported::representation [string cat [list] [list] [list x]] +} -match glob -result {*no string representation} +test string-29.10 {string cat, efficiency} -body { + tcl::unsupported::representation [string cat [list x] [list x]] +} -match glob -result {*, string representation "xx"} +test string-29.11 {string cat, efficiency} -body { + tcl::unsupported::representation \ + [string cat [list x] [encoding convertto utf-8 {}]] +} -match glob -result {*no string representation} +test string-29.12 {string cat, efficiency} -body { + tcl::unsupported::representation \ + [string cat [encoding convertto utf-8 {}] [list x]] +} -match glob -result {*, string representation "x"} +test string-29.13 {string cat, efficiency} -body { + tcl::unsupported::representation [string cat \ + [encoding convertto utf-8 {}] [encoding convertto utf-8 {}] [list x]] +} -match glob -result {*, string representation "x"} |