diff options
author | dgp <dgp@users.sourceforge.net> | 2016-03-23 15:19:05 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2016-03-23 15:19:05 (GMT) |
commit | 934b792db4a8904b39452dd7c300034db18200f2 (patch) | |
tree | 96d45885dc02d811393a10b22a2baf0a01ffffdb | |
parent | dcf7da567cfeb4dd11639161b001e4c23459b4ad (diff) | |
download | tcl-934b792db4a8904b39452dd7c300034db18200f2.zip tcl-934b792db4a8904b39452dd7c300034db18200f2.tar.gz tcl-934b792db4a8904b39452dd7c300034db18200f2.tar.bz2 |
Tcl_InitStringRep() bug. Truncation assumed length == allocated. Wrong!
Convert "bytearray" Tcl_ObjType to used new facilities. No longer directly
refers to bytes or length fields, or any ckalloc of string rep.
-rw-r--r-- | generic/tclBinary.c | 61 | ||||
-rw-r--r-- | generic/tclObj.c | 7 |
2 files changed, 31 insertions, 37 deletions
diff --git a/generic/tclBinary.c b/generic/tclBinary.c index 981f174..7abb5c5 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -15,6 +15,7 @@ #include "tommath.h" #include <math.h> +#include <assert.h> /* * The following constants are used by GetFormatSpec to indicate various @@ -195,9 +196,9 @@ const Tcl_ObjType tclByteArrayType = { */ typedef struct ByteArray { - int used; /* The number of bytes used in the byte + unsigned int used; /* The number of bytes used in the byte * array. */ - int allocated; /* The amount of space actually allocated + unsigned int allocated; /* The amount of space actually allocated * minus 1 byte. */ unsigned char bytes[1]; /* The array of bytes. The actual size of this * field depends on the 'allocated' field @@ -410,6 +411,10 @@ Tcl_SetByteArrayLength( int length) /* New length for internal byte array. */ { ByteArray *byteArrayPtr; + unsigned newLength; + + assert(length >= 0); + newLength = (unsigned int)length; if (Tcl_IsShared(objPtr)) { Tcl_Panic("%s called with shared object", "Tcl_SetByteArrayLength"); @@ -419,13 +424,13 @@ Tcl_SetByteArrayLength( } byteArrayPtr = GET_BYTEARRAY(objPtr); - if (length > byteArrayPtr->allocated) { - byteArrayPtr = ckrealloc(byteArrayPtr, BYTEARRAY_SIZE(length)); - byteArrayPtr->allocated = length; + if (newLength > byteArrayPtr->allocated) { + byteArrayPtr = ckrealloc(byteArrayPtr, BYTEARRAY_SIZE(newLength)); + byteArrayPtr->allocated = newLength; SET_BYTEARRAY(objPtr, byteArrayPtr); } TclInvalidateStringRep(objPtr); - byteArrayPtr->used = length; + byteArrayPtr->used = newLength; return byteArrayPtr->bytes; } @@ -523,7 +528,7 @@ DupByteArrayInternalRep( Tcl_Obj *srcPtr, /* Object with internal rep to copy. */ Tcl_Obj *copyPtr) /* Object with internal rep to set. */ { - int length; + unsigned int length; ByteArray *srcArrayPtr, *copyArrayPtr; srcArrayPtr = GET_BYTEARRAY(srcPtr); @@ -565,41 +570,32 @@ UpdateStringOfByteArray( Tcl_Obj *objPtr) /* ByteArray object whose string rep to * update. */ { - int i, length, size; - unsigned char *src; - char *dst; - ByteArray *byteArrayPtr; - - byteArrayPtr = GET_BYTEARRAY(objPtr); - src = byteArrayPtr->bytes; - length = byteArrayPtr->used; + ByteArray *byteArrayPtr = GET_BYTEARRAY(objPtr); + unsigned char *src = byteArrayPtr->bytes; + unsigned int i, length = byteArrayPtr->used; + unsigned int size = length; /* * How much space will string rep need? */ - size = length; - for (i = 0; i < length && size >= 0; i++) { + for (i = 0; i < length && size <= INT_MAX; i++) { if ((src[i] == 0) || (src[i] > 127)) { size++; } } - if (size < 0) { + if (size > INT_MAX) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } - dst = ckalloc(size + 1); - objPtr->bytes = dst; - objPtr->length = size; - if (size == length) { - memcpy(dst, src, (size_t) size); - dst[size] = '\0'; + (void) Tcl_InitStringRep(objPtr, (char *)src, size); } else { + char *dst = Tcl_InitStringRep(objPtr, NULL, size); for (i = 0; i < length; i++) { dst += Tcl_UniCharToUtf(src[i], dst); } - *dst = '\0'; + (void)Tcl_InitStringRep(objPtr, NULL, size); } } @@ -629,7 +625,7 @@ TclAppendBytesToByteArray( int len) { ByteArray *byteArrayPtr; - int needed; + unsigned int length, needed; if (Tcl_IsShared(objPtr)) { Tcl_Panic("%s called with shared object","TclAppendBytesToByteArray"); @@ -642,23 +638,24 @@ TclAppendBytesToByteArray( /* Append zero bytes is a no-op. */ return; } + length = (unsigned int)len; if (objPtr->typePtr != &tclByteArrayType) { SetByteArrayFromAny(NULL, objPtr); } byteArrayPtr = GET_BYTEARRAY(objPtr); - if (len > INT_MAX - byteArrayPtr->used) { + if (length > INT_MAX - byteArrayPtr->used) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } - needed = byteArrayPtr->used + len; + needed = byteArrayPtr->used + length; /* * If we need to, resize the allocated space in the byte array. */ if (needed > byteArrayPtr->allocated) { ByteArray *ptr = NULL; - int attempt; + unsigned int attempt; if (needed <= INT_MAX/2) { /* Try to allocate double the total space that is needed. */ @@ -668,7 +665,7 @@ TclAppendBytesToByteArray( if (ptr == NULL) { /* Try to allocate double the increment that is needed (plus). */ unsigned int limit = INT_MAX - needed; - unsigned int extra = len + TCL_MIN_GROWTH; + unsigned int extra = length + TCL_MIN_GROWTH; int growth = (int) ((extra > limit) ? limit : extra); attempt = needed + growth; @@ -685,9 +682,9 @@ TclAppendBytesToByteArray( } if (bytes) { - memcpy(byteArrayPtr->bytes + byteArrayPtr->used, bytes, len); + memcpy(byteArrayPtr->bytes + byteArrayPtr->used, bytes, length); } - byteArrayPtr->used += len; + byteArrayPtr->used += length; TclInvalidateStringRep(objPtr); } diff --git a/generic/tclObj.c b/generic/tclObj.c index 3fb344e..d1fde0e 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -1771,11 +1771,8 @@ Tcl_InitStringRep( } } else { /* objPtr->bytes != NULL bytes == NULL - Truncate */ - assert((int)numBytes <= objPtr->length); - if (objPtr->length > (int)numBytes) { - objPtr->bytes = (char *)ckrealloc(objPtr->bytes, numBytes+1); - objPtr->length = (int)numBytes; - } + objPtr->bytes = (char *)ckrealloc(objPtr->bytes, numBytes+1); + objPtr->length = (int)numBytes; } /* Terminate */ |