From a04bd79877fc0082c18a3b9f7afa934b9f67cfd0 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 7 Apr 2009 18:37:42 +0000 Subject: * generic/tclStringObj.c: Completed backports of fixes for [Bug 2494093] and [Bug 2553906]. --- ChangeLog | 5 ++ generic/tclStringObj.c | 179 +++++++++++++++++++++++++++++++------------------ 2 files changed, 118 insertions(+), 66 deletions(-) diff --git a/ChangeLog b/ChangeLog index f5360e2..a31480e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-04-07 Don Porter + + * generic/tclStringObj.c: Completed backports of fixes for + [Bug 2494093] and [Bug 2553906]. + 2009-03-30 Don Porter * doc/Alloc.3: Size argument is "unsigned int". [Bug 2556263] diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c index 6490bc6..14f3bac 100644 --- a/generic/tclStringObj.c +++ b/generic/tclStringObj.c @@ -33,7 +33,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclStringObj.c,v 1.32.2.8 2009/03/30 17:47:09 dgp Exp $ */ + * RCS: @(#) $Id: tclStringObj.c,v 1.32.2.9 2009/04/07 18:37:42 dgp Exp $ */ #include "tclInt.h" @@ -51,16 +51,17 @@ static void AppendUtfToUnicodeRep _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *bytes, int numBytes)); static void AppendUtfToUtfRep _ANSI_ARGS_((Tcl_Obj *objPtr, CONST char *bytes, int numBytes)); - -static void FillUnicodeRep _ANSI_ARGS_((Tcl_Obj *objPtr)); - -static void FreeStringInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr)); static void DupStringInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr, Tcl_Obj *copyPtr)); +static void FillUnicodeRep _ANSI_ARGS_((Tcl_Obj *objPtr)); +static void FreeStringInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr)); +static void GrowUnicodeBuffer _ANSI_ARGS_((Tcl_Obj *objPtr, + int needed)); static int SetStringFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr)); static void SetUnicodeObj(Tcl_Obj *objPtr, CONST Tcl_UniChar *unicode, int numChars); +static int UnicodeLength _ANSI_ARGS_((CONST Tcl_UniChar *unicode)); static void UpdateStringOfString _ANSI_ARGS_((Tcl_Obj *objPtr)); /* @@ -105,15 +106,25 @@ typedef struct String { * 'uallocated' field above. */ } String; +#define STRING_MAXCHARS \ + (1 + (int)(((size_t)UINT_MAX - sizeof(String))/sizeof(Tcl_UniChar))) #define STRING_UALLOC(numChars) \ - ((numChars) * sizeof(Tcl_UniChar)) + ((numChars) * sizeof(Tcl_UniChar)) #define STRING_SIZE(ualloc) \ ((unsigned) ((ualloc) \ - ? ((sizeof(String) - sizeof(Tcl_UniChar) + (ualloc) > INT_MAX) \ - ? Tcl_Panic("unable to alloc %u bytes", \ - sizeof(String) - sizeof(Tcl_UniChar) + (ualloc)), INT_MAX \ - : (sizeof(String) - sizeof(Tcl_UniChar) + (ualloc))) \ + ? (sizeof(String) - sizeof(Tcl_UniChar) + (ualloc)) \ : sizeof(String))) +#define stringCheckLimits(numChars) \ + if ((numChars) < 0 || (numChars) > STRING_MAXCHARS) { \ + Tcl_Panic("max length for a Tcl unicode value (%d chars) exceeded", \ + STRING_MAXCHARS); \ + } +#define stringRealloc(ptr, numChars) \ + (String *) ckrealloc((char *) ptr, \ + (unsigned) STRING_SIZE(STRING_UALLOC(numChars)) ) +#define stringAttemptRealloc(ptr, numChars) \ + (String *) attemptckrealloc((char *) ptr, \ + (unsigned) STRING_SIZE(STRING_UALLOC(numChars)) ) #define GET_STRING(objPtr) \ ((String *) (objPtr)->internalRep.otherValuePtr) #define SET_STRING(objPtr, stringPtr) \ @@ -157,6 +168,48 @@ typedef struct String { #define TCL_GROWTH_MIN_ALLOC 1024 #endif +static void +GrowUnicodeBuffer( + Tcl_Obj *objPtr, + int needed) +{ + /* Pre-conditions: + * objPtr->typePtr == &tclStringType + * STRING_UALLOC(needed) > stringPtr->uallocated + * needed < STRING_MAXCHARS + */ + String *ptr = NULL, *stringPtr = GET_STRING(objPtr); + int attempt; + + if (stringPtr->uallocated > 0) { + /* Subsequent appends - apply the growth algorithm. */ + attempt = 2 * needed; + if (attempt >= 0 && attempt <= STRING_MAXCHARS) { + ptr = stringAttemptRealloc(stringPtr, attempt); + } + if (ptr == NULL) { + /* + * Take care computing the amount of modest growth to avoid + * overflow into invalid argument values for attempt. + */ + unsigned int limit = STRING_MAXCHARS - needed; + unsigned int extra = needed - stringPtr->numChars + + TCL_GROWTH_MIN_ALLOC/sizeof(Tcl_UniChar); + int growth = (int) ((extra > limit) ? limit : extra); + attempt = needed + growth; + ptr = stringAttemptRealloc(stringPtr, attempt); + } + } + if (ptr == NULL) { + /* First allocation - just big enough; or last chance fallback. */ + attempt = needed; + ptr = stringRealloc(stringPtr, attempt); + } + stringPtr = ptr; + stringPtr->uallocated = STRING_UALLOC(attempt); + SET_STRING(objPtr, stringPtr); +} + /* *---------------------------------------------------------------------- @@ -797,9 +850,10 @@ Tcl_SetObjLength(objPtr, length) } else { /* Changing length of pure unicode string */ size_t uallocated = STRING_UALLOC(length); + + stringCheckLimits(length); if (uallocated > stringPtr->uallocated) { - stringPtr = (String *) ckrealloc((char*) stringPtr, - STRING_SIZE(uallocated)); + stringPtr = stringRealloc(stringPtr, length); SET_STRING(objPtr, stringPtr); stringPtr->uallocated = uallocated; } @@ -905,9 +959,12 @@ Tcl_AttemptSetObjLength(objPtr, length) } else { /* Changing length of pure unicode string */ size_t uallocated = STRING_UALLOC(length); + if (length > STRING_MAXCHARS) { + return 0; + } + if (uallocated > stringPtr->uallocated) { - stringPtr = (String *) attemptckrealloc((char*) stringPtr, - STRING_SIZE(uallocated)); + stringPtr = stringAttemptRealloc(stringPtr, length); if (stringPtr == NULL) { return 0; } @@ -959,6 +1016,21 @@ Tcl_SetUnicodeObj(objPtr, unicode, numChars) SetUnicodeObj(objPtr, unicode, numChars); } +static int +UnicodeLength( + const Tcl_UniChar *unicode) +{ + int numChars = 0; + + if (unicode) { + while (numChars >= 0 && unicode[numChars] != 0) { + numChars++; + } + } + stringCheckLimits(numChars); + return numChars; +} + static void SetUnicodeObj(objPtr, unicode, numChars) Tcl_Obj *objPtr; /* The object to set the string of. */ @@ -971,16 +1043,14 @@ SetUnicodeObj(objPtr, unicode, numChars) size_t uallocated; if (numChars < 0) { - numChars = 0; - if (unicode) { - while (unicode[numChars] != 0) { numChars++; } - } + numChars = UnicodeLength(unicode); } /* * Allocate enough space for the String structure + Unicode string. */ + stringCheckLimits(numChars); uallocated = STRING_UALLOC(numChars); stringPtr = (String *) ckalloc(STRING_SIZE(uallocated)); @@ -1215,14 +1285,11 @@ AppendUnicodeToUnicodeRep(objPtr, unicode, appendNumChars) CONST Tcl_UniChar *unicode; /* String to append. */ int appendNumChars; /* Number of chars of "unicode" to append. */ { - String *stringPtr, *tmpString; + String *stringPtr; size_t numChars; if (appendNumChars < 0) { - appendNumChars = 0; - if (unicode) { - while (unicode[appendNumChars] != 0) { appendNumChars++; } - } + appendNumChars = UnicodeLength(unicode); } if (appendNumChars == 0) { return; @@ -1240,6 +1307,7 @@ AppendUnicodeToUnicodeRep(objPtr, unicode, appendNumChars) */ numChars = stringPtr->numChars + appendNumChars; + stringCheckLimits(numChars); if (STRING_UALLOC(numChars) >= stringPtr->uallocated) { /* @@ -1253,18 +1321,8 @@ AppendUnicodeToUnicodeRep(objPtr, unicode, appendNumChars) offset = unicode - stringPtr->unicode; } - stringPtr->uallocated = STRING_UALLOC(2 * numChars); - tmpString = (String *) attemptckrealloc((char *)stringPtr, - STRING_SIZE(stringPtr->uallocated)); - if (tmpString == NULL) { - stringPtr->uallocated = - STRING_UALLOC(numChars + appendNumChars) - + TCL_GROWTH_MIN_ALLOC; - tmpString = (String *) ckrealloc((char *)stringPtr, - STRING_SIZE(stringPtr->uallocated)); - } - stringPtr = tmpString; - SET_STRING(objPtr, stringPtr); + GrowUnicodeBuffer(objPtr, numChars); + stringPtr = GET_STRING(objPtr); /* Relocate unicode if needed; see above. */ if (offset >= 0) { @@ -1312,10 +1370,7 @@ AppendUnicodeToUtfRep(objPtr, unicode, numChars) CONST char *bytes; if (numChars < 0) { - numChars = 0; - if (unicode) { - while (unicode[numChars] != 0) { numChars++; } - } + numChars = UnicodeLength(unicode); } if (numChars == 0) { return; @@ -1408,10 +1463,10 @@ AppendUtfToUtfRep(objPtr, bytes, numBytes) */ oldLength = objPtr->length; - if (numBytes > INT_MAX - oldLength) { + newLength = numBytes + oldLength; + if (newLength < 0) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } - newLength = numBytes + oldLength; stringPtr = GET_STRING(objPtr); if (newLength > (int) stringPtr->allocated) { @@ -1677,28 +1732,11 @@ FillUnicodeRep(objPtr) } stringPtr->hasUnicode = (stringPtr->numChars > 0); + stringCheckLimits(stringPtr->numChars); uallocated = STRING_UALLOC(stringPtr->numChars); if (uallocated > stringPtr->uallocated) { - - /* - * If not enough space has been allocated for the unicode rep, - * reallocate the internal rep object. - */ - - /* - * There isn't currently enough space in the Unicode - * representation so allocate additional space. If the current - * Unicode representation isn't empty (i.e. it looks like we've - * done some appends) then overallocate the space so - * that we won't have to do as much reallocation in the future. - */ - - if (stringPtr->uallocated > 0) { - uallocated *= 2; - } - stringPtr = (String *) ckrealloc((char*) stringPtr, - STRING_SIZE(uallocated)); - stringPtr->uallocated = uallocated; + GrowUnicodeBuffer(objPtr, stringPtr->numChars); + stringPtr = GET_STRING(objPtr); } /* @@ -1750,8 +1788,8 @@ DupStringInternalRep(srcPtr, copyPtr) */ if (srcStringPtr->hasUnicode == 0) { - copyStringPtr = (String *) ckalloc(STRING_SIZE(STRING_UALLOC(0))); - copyStringPtr->uallocated = STRING_UALLOC(0); + copyStringPtr = (String *) ckalloc(sizeof(String)); + copyStringPtr->uallocated = 0; } else { copyStringPtr = (String *) ckalloc( STRING_SIZE(srcStringPtr->uallocated)); @@ -1823,9 +1861,9 @@ SetStringFromAny(interp, objPtr) * Allocate enough space for the basic String structure. */ - stringPtr = (String *) ckalloc(STRING_SIZE(STRING_UALLOC(0))); + stringPtr = (String *) ckalloc(sizeof(String)); stringPtr->numChars = -1; - stringPtr->uallocated = STRING_UALLOC(0); + stringPtr->uallocated = 0; stringPtr->hasUnicode = 0; if (objPtr->bytes != NULL) { @@ -1889,17 +1927,26 @@ UpdateStringOfString(objPtr) * amount of space the UTF string needs. */ + if (stringPtr->numChars <= INT_MAX/TCL_UTF_MAX + && stringPtr->allocated >= stringPtr->numChars * TCL_UTF_MAX) { + goto copyBytes; + } + size = 0; for (i = 0; i < stringPtr->numChars; i++) { size += Tcl_UniCharToUtf((int) unicode[i], dummy); } + if (size < 0) { + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); + } dst = (char *) ckalloc((unsigned) (size + 1)); objPtr->bytes = dst; objPtr->length = size; stringPtr->allocated = size; - for (i = 0; i < stringPtr->numChars; i++) { + copyBytes: + for (i = 0; i < stringPtr->numChars && size >= 0; i++) { dst += Tcl_UniCharToUtf(unicode[i], dst); } *dst = '\0'; -- cgit v0.12