Index: generic/tclBinary.c ================================================================== --- generic/tclBinary.c +++ generic/tclBinary.c @@ -53,17 +53,14 @@ /* * Prototypes for local procedures defined in this file: */ -static void DupByteArrayInternalRep(Tcl_Obj *srcPtr, - Tcl_Obj *copyPtr); static void DupProperByteArrayInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); static int FormatNumber(Tcl_Interp *interp, int type, Tcl_Obj *src, unsigned char **cursorPtr); -static void FreeByteArrayInternalRep(Tcl_Obj *objPtr); static void FreeProperByteArrayInternalRep(Tcl_Obj *objPtr); static int GetFormatSpec(const char **formatPtr, char *cmdPtr, size_t *countPtr, int *flagsPtr); static Tcl_Obj * ScanNumber(unsigned char *buffer, int type, int flags, Tcl_HashTable **numberCachePtr); @@ -162,14 +159,10 @@ * The following object types represent an array of bytes. The intent is * to allow arbitrary binary data to pass through Tcl as a Tcl value * without loss or damage. Such values are useful for things like * encoded strings or Tk images to name just two. * - * It's strange to have two Tcl_ObjTypes in place for this task when - * one would do, so a bit of detail and history how we got to this point - * and where we might go from here. - * * A bytearray is an ordered sequence of bytes. Each byte is an integer * value in the range [0-255]. To be a Tcl value type, we need a way to * encode each value in the value set as a Tcl string. The simplest * encoding is to represent each byte value as the same codepoint value. * A bytearray of N bytes is encoded into a Tcl string of N characters @@ -254,18 +247,10 @@ DupProperByteArrayInternalRep, UpdateStringOfByteArray, NULL }; -const Tcl_ObjType tclByteArrayType = { - "bytearray", - FreeByteArrayInternalRep, - DupByteArrayInternalRep, - NULL, - SetByteArrayFromAny -}; - /* * The following structure is the internal rep for a ByteArray object. Keeps * track of how much memory has been used and how much has been allocated for * the byte array to enable growing and shrinking of the ByteArray object with * fewer mallocs. @@ -449,18 +434,17 @@ { ByteArray *baPtr; const Tcl_ObjIntRep *irPtr = TclFetchIntRep(objPtr, &properByteArrayType); if (irPtr == NULL) { - irPtr = TclFetchIntRep(objPtr, &tclByteArrayType); - if (irPtr == NULL) { - SetByteArrayFromAny(NULL, objPtr); - irPtr = TclFetchIntRep(objPtr, &properByteArrayType); - if (irPtr == NULL) { - irPtr = TclFetchIntRep(objPtr, &tclByteArrayType); - } - } + if (TCL_ERROR == SetByteArrayFromAny(NULL, objPtr)) { + if (lengthPtr != NULL) { + *lengthPtr = 0; + } + return NULL; + } + irPtr = TclFetchIntRep(objPtr, &properByteArrayType); } baPtr = GET_BYTEARRAY(irPtr); if (lengthPtr != NULL) { *lengthPtr = baPtr->used; @@ -491,11 +475,11 @@ */ unsigned char * Tcl_SetByteArrayLength( Tcl_Obj *objPtr, /* The ByteArray object. */ - size_t length) /* New length for internal byte array. */ + size_t length) /* New length for internal byte array. */ { ByteArray *byteArrayPtr; Tcl_ObjIntRep *irPtr; if (Tcl_IsShared(objPtr)) { @@ -502,18 +486,16 @@ Tcl_Panic("%s called with shared object", "Tcl_SetByteArrayLength"); } irPtr = TclFetchIntRep(objPtr, &properByteArrayType); if (irPtr == NULL) { - irPtr = TclFetchIntRep(objPtr, &tclByteArrayType); - if (irPtr == NULL) { - SetByteArrayFromAny(NULL, objPtr); - irPtr = TclFetchIntRep(objPtr, &properByteArrayType); - if (irPtr == NULL) { - irPtr = TclFetchIntRep(objPtr, &tclByteArrayType); - } - } + if (length == 0) { + Tcl_SetByteArrayObj(objPtr, NULL, 0); + } else if (TCL_ERROR == SetByteArrayFromAny(NULL, objPtr)) { + return NULL; + } + irPtr = TclFetchIntRep(objPtr, &properByteArrayType); } byteArrayPtr = GET_BYTEARRAY(irPtr); if (length > byteArrayPtr->allocated) { byteArrayPtr = Tcl_Realloc(byteArrayPtr, BYTEARRAY_SIZE(length)); @@ -538,47 +520,80 @@ * Side effects: * A ByteArray object is stored as the internal rep of objPtr. * *---------------------------------------------------------------------- */ + +static int +MakeByteArray( + Tcl_Obj *objPtr, + int earlyOut, + ByteArray **byteArrayPtrPtr) +{ + int length, proper = 1; + unsigned char *dst; + const char *src = TclGetStringFromObj(objPtr, &length); + ByteArray *byteArrayPtr = Tcl_Alloc(BYTEARRAY_SIZE(length)); + const char *srcEnd = src + length; + Tcl_UniChar ch = 0; + + for (dst = byteArrayPtr->bytes; src < srcEnd; ) { + src += TclUtfToUniChar(src, &ch); + if (ch > 255) { + proper = 0; + if (earlyOut) { + ckfree(byteArrayPtr); + *byteArrayPtrPtr = NULL; + return proper; + } + } + *dst++ = UCHAR(ch); + } + byteArrayPtr->used = dst - byteArrayPtr->bytes; + byteArrayPtr->allocated = length; + + *byteArrayPtrPtr = byteArrayPtr; + return proper; +} + +Tcl_Obj * +TclNarrowToBytes( + Tcl_Obj *objPtr) +{ + if (NULL == TclFetchIntRep(objPtr, &properByteArrayType)) { + Tcl_ObjIntRep ir; + ByteArray *byteArrayPtr; + + if (0 == MakeByteArray(objPtr, 0, &byteArrayPtr)) { + objPtr = Tcl_NewObj(); + TclInvalidateStringRep(objPtr); + } + SET_BYTEARRAY(&ir, byteArrayPtr); + Tcl_StoreIntRep(objPtr, &properByteArrayType, &ir); + } + Tcl_IncrRefCount(objPtr); + return objPtr; +} static int SetByteArrayFromAny( Tcl_Interp *interp, /* Not used. */ Tcl_Obj *objPtr) /* The object to convert to type ByteArray. */ { - size_t length; - int improper = 0; - const char *src, *srcEnd; - unsigned char *dst; - Tcl_UniChar ch = 0; ByteArray *byteArrayPtr; Tcl_ObjIntRep ir; if (TclHasIntRep(objPtr, &properByteArrayType)) { return TCL_OK; } - if (TclHasIntRep(objPtr, &tclByteArrayType)) { - return TCL_OK; - } - - src = TclGetStringFromObj(objPtr, &length); - srcEnd = src + length; - - byteArrayPtr = Tcl_Alloc(BYTEARRAY_SIZE(length)); - for (dst = byteArrayPtr->bytes; src < srcEnd; ) { - src += TclUtfToUniChar(src, &ch); - improper = improper || (ch > 255); - *dst++ = UCHAR(ch); - } - - byteArrayPtr->used = dst - byteArrayPtr->bytes; - byteArrayPtr->allocated = length; + + if (0 == MakeByteArray(objPtr, 1, &byteArrayPtr)) { + return TCL_ERROR; + } SET_BYTEARRAY(&ir, byteArrayPtr); - Tcl_StoreIntRep(objPtr, - improper ? &tclByteArrayType : &properByteArrayType, &ir); + Tcl_StoreIntRep(objPtr, &properByteArrayType, &ir); return TCL_OK; } /* *---------------------------------------------------------------------- @@ -595,17 +610,10 @@ * Frees memory. * *---------------------------------------------------------------------- */ -static void -FreeByteArrayInternalRep( - Tcl_Obj *objPtr) /* Object with internal rep to free. */ -{ - Tcl_Free(GET_BYTEARRAY(TclFetchIntRep(objPtr, &tclByteArrayType))); -} - static void FreeProperByteArrayInternalRep( Tcl_Obj *objPtr) /* Object with internal rep to free. */ { Tcl_Free(GET_BYTEARRAY(TclFetchIntRep(objPtr, &properByteArrayType))); @@ -627,36 +635,15 @@ * *---------------------------------------------------------------------- */ static void -DupByteArrayInternalRep( +DupProperByteArrayInternalRep( Tcl_Obj *srcPtr, /* Object with internal rep to copy. */ Tcl_Obj *copyPtr) /* Object with internal rep to set. */ { size_t length; - ByteArray *srcArrayPtr, *copyArrayPtr; - Tcl_ObjIntRep ir; - - srcArrayPtr = GET_BYTEARRAY(TclFetchIntRep(srcPtr, &tclByteArrayType)); - length = srcArrayPtr->used; - - copyArrayPtr = Tcl_Alloc(BYTEARRAY_SIZE(length)); - copyArrayPtr->used = length; - copyArrayPtr->allocated = length; - memcpy(copyArrayPtr->bytes, srcArrayPtr->bytes, length); - - SET_BYTEARRAY(&ir, copyArrayPtr); - Tcl_StoreIntRep(copyPtr, &tclByteArrayType, &ir); -} - -static void -DupProperByteArrayInternalRep( - Tcl_Obj *srcPtr, /* Object with internal rep to copy. */ - Tcl_Obj *copyPtr) /* Object with internal rep to set. */ -{ - unsigned int length; ByteArray *srcArrayPtr, *copyArrayPtr; Tcl_ObjIntRep ir; srcArrayPtr = GET_BYTEARRAY(TclFetchIntRep(srcPtr, &properByteArrayType)); length = srcArrayPtr->used; @@ -762,18 +749,14 @@ return; } irPtr = TclFetchIntRep(objPtr, &properByteArrayType); if (irPtr == NULL) { - irPtr = TclFetchIntRep(objPtr, &tclByteArrayType); - if (irPtr == NULL) { - SetByteArrayFromAny(NULL, objPtr); - irPtr = TclFetchIntRep(objPtr, &properByteArrayType); - if (irPtr == NULL) { - irPtr = TclFetchIntRep(objPtr, &tclByteArrayType); - } - } + if (TCL_ERROR == SetByteArrayFromAny(NULL, objPtr)) { + Tcl_Panic("attempt to append bytes to non-bytearray"); + } + irPtr = TclFetchIntRep(objPtr, &properByteArrayType); } byteArrayPtr = GET_BYTEARRAY(irPtr); if (len > UINT_MAX - byteArrayPtr->used) { Tcl_Panic("max size for a Tcl value (%u bytes) exceeded", UINT_MAX); @@ -925,11 +908,13 @@ if (arg >= objc) { goto badIndex; } if (count == BINARY_ALL) { - (void)TclGetByteArrayFromObj(objv[arg], &count); + Tcl_Obj *copy = TclNarrowToBytes(objv[arg]); + (void)TclGetByteArrayFromObj(copy, &count); + Tcl_DecrRefCount(copy); } else if (count == BINARY_NOCOUNT) { count = 1; } arg++; if (cmd == 'a' || cmd == 'A') { @@ -1088,13 +1073,14 @@ switch (cmd) { case 'a': case 'A': { char pad = (char) (cmd == 'a' ? '\0' : ' '); unsigned char *bytes; + Tcl_Obj *copy = TclNarrowToBytes(objv[arg++]); - bytes = TclGetByteArrayFromObj(objv[arg], &length); - arg++; + bytes = TclGetByteArrayFromObj(copy, &length); + if (count == BINARY_ALL) { count = length; } else if (count == BINARY_NOCOUNT) { count = 1; } @@ -1103,10 +1089,11 @@ } else { memcpy(cursor, bytes, length); memset(cursor + length, pad, count - length); } cursor += count; + Tcl_DecrRefCount(copy); break; } case 'b': case 'B': { unsigned char *last; @@ -1400,14 +1387,18 @@ if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "value formatString ?varName ...?"); return TCL_ERROR; + } + buffer = TclGetByteArrayFromObj(objv[1], &length); + if (buffer == NULL) { + Tcl_AppendResult(interp, "binary scan expects bytes", NULL); + return TCL_ERROR; } numberCachePtr = &numberCacheHash; Tcl_InitHashTable(numberCachePtr, TCL_ONE_WORD_KEYS); - buffer = TclGetByteArrayFromObj(objv[1], &length); format = TclGetString(objv[2]); arg = 3; offset = 0; while (*format != '\0') { str = format; @@ -2451,12 +2442,17 @@ if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "data"); return TCL_ERROR; } - TclNewObj(resultObj); data = TclGetByteArrayFromObj(objv[1], &count); + if (data == NULL) { + Tcl_AppendResult(interp, "binary encode expects bytes", NULL); + return TCL_ERROR; + } + + TclNewObj(resultObj); cursor = Tcl_SetByteArrayLength(resultObj, count * 2); for (offset = 0; offset < count; ++offset) { *cursor++ = HexDigits[((data[offset] >> 4) & 0x0f)]; *cursor++ = HexDigits[(data[offset] & 0x0f)]; } @@ -2647,12 +2643,16 @@ } break; } } - resultObj = Tcl_NewObj(); data = TclGetByteArrayFromObj(objv[objc-1], &count); + if (data == NULL) { + Tcl_AppendResult(interp, "binary encode expects bytes", NULL); + return TCL_ERROR; + } + resultObj = Tcl_NewObj(); if (count > 0) { size = (((count * 4) / 3) + 3) & ~3; /* ensure 4 byte chunks */ if (maxlen > 0 && size > maxlen) { int adjusted = size + (wrapcharlen * (size / maxlen)); @@ -2747,22 +2747,31 @@ return TCL_ERROR; } break; case OPT_WRAPCHAR: wrapchar = TclGetByteArrayFromObj(objv[i+1], &wrapcharlen); + if (wrapchar == NULL) { + Tcl_AppendResult(interp, + "binary encode -wrapchar expects bytes", NULL); + return TCL_ERROR; + } break; } } /* * Allocate the buffer. This is a little bit too long, but is "good * enough". */ - resultObj = Tcl_NewObj(); offset = 0; data = TclGetByteArrayFromObj(objv[objc-1], &count); + if (data == NULL) { + Tcl_AppendResult(interp, "binary encode expects bytes", NULL); + return TCL_ERROR; + } + resultObj = Tcl_NewObj(); rawLength = (lineLength - 1) * 3 / 4; start = cursor = Tcl_SetByteArrayLength(resultObj, (lineLength + wrapcharlen) * ((count + (rawLength - 1)) / rawLength)); n = bits = 0; Index: generic/tclCmdAH.c ================================================================== --- generic/tclCmdAH.c +++ generic/tclCmdAH.c @@ -446,10 +446,15 @@ /* * Convert the string into a byte array in 'ds' */ bytesPtr = (char *) TclGetByteArrayFromObj(data, &length); + if (bytesPtr == NULL) { + Tcl_AppendResult(interp, "encoding conversion expects bytes", NULL); + Tcl_FreeEncoding(encoding); + return TCL_ERROR; + } Tcl_ExternalToUtfDString(encoding, bytesPtr, length, &ds); /* * Note that we cannot use Tcl_DStringResult here because it will * truncate the string at the first null byte. Index: generic/tclIO.c ================================================================== --- generic/tclIO.c +++ generic/tclIO.c @@ -4116,11 +4116,11 @@ * strlen(). */ { Channel *chanPtr = (Channel *) chan; ChannelState *statePtr = chanPtr->state; /* State info for channel */ int result; - Tcl_Obj *objPtr; + Tcl_Obj *objPtr, *copy; if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) { return TCL_IO_FAILURE; } @@ -4143,13 +4143,15 @@ if ((len == 1) && (UCHAR(*src) < 0xC0)) { return WriteBytes(chanPtr, src, len); } objPtr = Tcl_NewStringObj(src, len); - src = (char *) TclGetByteArrayFromObj(objPtr, &len); - result = WriteBytes(chanPtr, src, len); + copy = TclNarrowToBytes(objPtr); + src = (char *) TclGetByteArrayFromObj(copy, &len); TclDecrRefCount(objPtr); + result = WriteBytes(chanPtr, src, len); + TclDecrRefCount(copy); return result; } /* *--------------------------------------------------------------------------- @@ -4195,12 +4197,17 @@ if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) { return TCL_IO_FAILURE; } if (statePtr->encoding == NULL) { - src = (char *) TclGetByteArrayFromObj(objPtr, &srcLen); - return WriteBytes(chanPtr, src, srcLen); + int result; + Tcl_Obj *copy = TclNarrowToBytes(objPtr); + + src = (char *) TclGetByteArrayFromObj(copy, &srcLen); + result = WriteBytes(chanPtr, src, srcLen); + Tcl_DecrRefCount(copy); + return result; } else { src = TclGetStringFromObj(objPtr, &srcLen); return WriteChars(chanPtr, src, srcLen); } } @@ -4555,11 +4562,12 @@ * done on objPtr. */ if ((statePtr->encoding == NULL) && ((statePtr->inputTranslation == TCL_TRANSLATE_LF) - || (statePtr->inputTranslation == TCL_TRANSLATE_CR))) { + || (statePtr->inputTranslation == TCL_TRANSLATE_CR)) + && Tcl_GetByteArrayFromObj(objPtr, NULL) != NULL) { return TclGetsObjBinary(chan, objPtr); } /* * This operation should occur at the top of a channel stack. Index: generic/tclIOGT.c ================================================================== --- generic/tclIOGT.c +++ generic/tclIOGT.c @@ -442,28 +442,41 @@ if (dataPtr->self == NULL) { break; } resObj = Tcl_GetObjResult(eval); resBuf = TclGetByteArrayFromObj(resObj, &resLen); - Tcl_WriteRaw(Tcl_GetStackedChannel(dataPtr->self), (char *) resBuf, - resLen); - break; + if (resBuf) { + Tcl_WriteRaw(Tcl_GetStackedChannel(dataPtr->self), + (char *) resBuf, resLen); + break; + } + goto nonBytes; case TRANSMIT_SELF: if (dataPtr->self == NULL) { break; } resObj = Tcl_GetObjResult(eval); resBuf = TclGetByteArrayFromObj(resObj, &resLen); - Tcl_WriteRaw(dataPtr->self, (char *) resBuf, resLen); - break; + if (resBuf) { + Tcl_WriteRaw(dataPtr->self, (char *) resBuf, resLen); + break; + } + goto nonBytes; case TRANSMIT_IBUF: resObj = Tcl_GetObjResult(eval); resBuf = TclGetByteArrayFromObj(resObj, &resLen); - ResultAdd(&dataPtr->result, resBuf, resLen); - break; + if (resBuf) { + ResultAdd(&dataPtr->result, resBuf, resLen); + break; + } + nonBytes: + Tcl_AppendResult(interp, "chan transform callback received non-bytes", + NULL); + Tcl_Release(eval); + return TCL_ERROR; case TRANSMIT_NUM: /* * Interpret result as integer number. */ Index: generic/tclIORChan.c ================================================================== --- generic/tclIORChan.c +++ generic/tclIORChan.c @@ -446,10 +446,11 @@ * Tcl lists where the last element is the message itself. Hence the * list-quoting to keep the words of the message together. See also [x]. */ static const char *msg_read_toomuch = "{read delivered more than requested}"; +static const char *msg_read_nonbyte = "{read delivered nonbyte result}"; static const char *msg_write_toomuch = "{write wrote more than requested}"; static const char *msg_write_nothing = "{write wrote nothing}"; static const char *msg_seek_beforestart = "{Tried to seek before origin}"; #if TCL_THREADS static const char *msg_send_originlost = "{Channel thread lost}"; @@ -1316,11 +1317,14 @@ goto invalid; } bytev = TclGetByteArrayFromObj(resObj, &bytec); - if ((size_t)toRead < bytec) { + if (bytev == NULL) { + SetChannelErrorStr(rcPtr->chan, msg_read_nonbyte); + goto invalid; + } else if ((size_t)toRead < bytec) { SetChannelErrorStr(rcPtr->chan, msg_read_toomuch); goto invalid; } *errorCodePtr = EOK; @@ -3001,11 +3005,14 @@ size_t bytec = 0; /* Number of returned bytes */ unsigned char *bytev; /* Array of returned bytes */ bytev = TclGetByteArrayFromObj(resObj, &bytec); - if (paramPtr->input.toRead < bytec) { + if (bytev == NULL) { + ForwardSetStaticError(paramPtr, msg_read_nonbyte); + paramPtr->input.toRead = -1; + } else if (paramPtr->input.toRead < bytec) { ForwardSetStaticError(paramPtr, msg_read_toomuch); paramPtr->input.toRead = TCL_IO_FAILURE; } else { if (bytec + 1 > 1) { memcpy(paramPtr->input.buf, bytev, bytec); Index: generic/tclInt.h ================================================================== --- generic/tclInt.h +++ generic/tclInt.h @@ -2676,11 +2676,10 @@ * Variables denoting the Tcl object types defined in the core. */ MODULE_SCOPE const Tcl_ObjType tclBignumType; MODULE_SCOPE const Tcl_ObjType tclBooleanType; -MODULE_SCOPE const Tcl_ObjType tclByteArrayType; MODULE_SCOPE const Tcl_ObjType tclByteCodeType; MODULE_SCOPE const Tcl_ObjType tclDoubleType; MODULE_SCOPE const Tcl_ObjType tclIntType; MODULE_SCOPE const Tcl_ObjType tclListType; MODULE_SCOPE const Tcl_ObjType tclDictType; @@ -3030,10 +3029,11 @@ MODULE_SCOPE int TclMaxListLength(const char *bytes, size_t numBytes, const char **endPtr); MODULE_SCOPE int TclMergeReturnOptions(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Obj **optionsPtrPtr, int *codePtr, int *levelPtr); +MODULE_SCOPE Tcl_Obj * TclNarrowToBytes(Tcl_Obj *objPtr); MODULE_SCOPE Tcl_Obj * TclNoErrorStack(Tcl_Interp *interp, Tcl_Obj *options); MODULE_SCOPE int TclNokia770Doubles(void); MODULE_SCOPE void TclNsDecrRefCount(Namespace *nsPtr); MODULE_SCOPE void TclObjVarErrMsg(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, const char *operation, Index: generic/tclObj.c ================================================================== --- generic/tclObj.c +++ generic/tclObj.c @@ -372,11 +372,10 @@ Tcl_MutexLock(&tableMutex); typeTableInitialized = 1; Tcl_InitHashTable(&typeTable, TCL_STRING_KEYS); Tcl_MutexUnlock(&tableMutex); - Tcl_RegisterObjType(&tclByteArrayType); Tcl_RegisterObjType(&tclDoubleType); Tcl_RegisterObjType(&tclStringType); Tcl_RegisterObjType(&tclListType); Tcl_RegisterObjType(&tclDictType); Tcl_RegisterObjType(&tclByteCodeType); Index: generic/tclTest.c ================================================================== --- generic/tclTest.c +++ generic/tclTest.c @@ -5018,10 +5018,14 @@ if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "bytearray"); return TCL_ERROR; } p = (const char *)Tcl_GetByteArrayFromObj(objv[1], &n); + if (p == NULL) { + Tcl_AppendResult(interp, "testbytestring expects bytes", NULL); + return TCL_ERROR; + } Tcl_SetObjResult(interp, Tcl_NewStringObj(p, n)); return TCL_OK; } /* Index: tests/binary.test ================================================================== --- tests/binary.test +++ tests/binary.test @@ -2914,11 +2914,11 @@ test binary-78.1 {unicode (out of BMP) to byte-array conversion, bug-[bd94500678]} -body { # just test for BO-segfault (high surrogate w/o advance source pointer for out of BMP char if TCL_UTF_MAX <= 4): binary encode hex \U0001f415 binary scan \U0001f415 a* v; set v set str {} -} -result {} +} -result * -match glob -returnCodes error # ---------------------------------------------------------------------- # cleanup ::tcltest::cleanupTests Index: tests/execute.test ================================================================== --- tests/execute.test +++ tests/execute.test @@ -987,11 +987,11 @@ } set result } SUCCESS test execute-10.1 {TclExecuteByteCode, INST_CONCAT1, bytearrays} { - apply {s {binary scan $s c x; list $x [scan $s$s %c%c]}} \u0130 + apply {s {binary scan [binary format a $s] c x; list $x [scan $s$s %c%c]}} \u0130 } {48 {304 304}} test execute-10.2 {Bug 2802881} -setup { interp create slave } -body { # If [Bug 2802881] is not fixed, this will segfault Index: tests/obj.test ================================================================== --- tests/obj.test +++ tests/obj.test @@ -24,11 +24,10 @@ testConstraint wideIs64bit [expr {wide(0x8000000000000000) < 0}] test obj-1.1 {Tcl_AppendAllObjTypes, and InitTypeTable, Tcl_RegisterObjType} testobj { set r 1 foreach {t} { - bytearray bytecode cmdName dict regexp string @@ -44,14 +43,14 @@ } {0 1 {no type foo found}} test obj-2.2 {Tcl_GetObjType and Tcl_ConvertToType} testobj { set result "" lappend result [testobj freeallvars] lappend result [testintobj set 1 12] - lappend result [testobj convert 1 bytearray] + lappend result [testobj convert 1 string] lappend result [testobj type 1] lappend result [testobj refcount 1] -} {{} 12 12 bytearray 3} +} {{} 12 12 string 3} test obj-4.1 {Tcl_NewObj and AllocateFreeObjects} testobj { set result "" lappend result [testobj freeallvars] lappend result [testobj newobj 1]