summaryrefslogtreecommitdiffstats
path: root/generic/tclStringObj.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclStringObj.c')
-rw-r--r--generic/tclStringObj.c179
1 files changed, 113 insertions, 66 deletions
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';