diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2022-11-18 21:43:40 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2022-11-18 21:43:40 (GMT) |
commit | 1c1ee1c59dab10aa856f9ecc8a2e9613aa69c04e (patch) | |
tree | 1bea67c3baaaa170b17938ea61b1b510e07a63e0 /generic/tclLink.c | |
parent | b3caf035b4e0afcd1686d6ac3190f6e0970e8199 (diff) | |
download | tcl-1c1ee1c59dab10aa856f9ecc8a2e9613aa69c04e.zip tcl-1c1ee1c59dab10aa856f9ecc8a2e9613aa69c04e.tar.gz tcl-1c1ee1c59dab10aa856f9ecc8a2e9613aa69c04e.tar.bz2 |
Backout [52a52a65f0], let's see if this fixes the Windows crash
Diffstat (limited to 'generic/tclLink.c')
-rw-r--r-- | generic/tclLink.c | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/generic/tclLink.c b/generic/tclLink.c index cd2c731..1973067 100644 --- a/generic/tclLink.c +++ b/generic/tclLink.c @@ -526,14 +526,56 @@ GetUWide( Tcl_Obj *objPtr, Tcl_WideUInt *uwidePtr) { - if (Tcl_GetWideUIntFromObj(NULL, objPtr, uwidePtr) != TCL_OK) { - int intValue; - - if (GetInvalidIntFromObj(objPtr, &intValue) != TCL_OK) { - return 1; + Tcl_WideInt *widePtr = (Tcl_WideInt *) uwidePtr; + void *clientData; + int type, intValue; + + if (Tcl_GetNumberFromObj(NULL, objPtr, &clientData, &type) == TCL_OK) { + if (type == TCL_NUMBER_INT) { + *widePtr = *((const Tcl_WideInt *) clientData); + return (*widePtr < 0); + } else if (type == TCL_NUMBER_BIG) { + mp_int *numPtr = (mp_int *)clientData; + Tcl_WideUInt value = 0; + union { + Tcl_WideUInt value; + unsigned char bytes[sizeof(Tcl_WideUInt)]; + } scratch; + size_t numBytes; + unsigned char *bytes = scratch.bytes; + + if (numPtr->sign || (MP_OKAY != mp_to_ubin(numPtr, + bytes, sizeof(Tcl_WideUInt), &numBytes))) { + /* + * If the sign bit is set (a negative value) or if the value + * can't possibly fit in the bits of an unsigned wide, there's + * no point in doing further conversion. + */ + return 1; + } +#ifndef WORDS_BIGENDIAN + while (numBytes-- > 0) { + value = (value << CHAR_BIT) | *bytes++; + } +#else /* WORDS_BIGENDIAN */ + /* + * Big-endian can read the value directly. + */ + value = scratch.value; +#endif /* WORDS_BIGENDIAN */ + *uwidePtr = value; + return 0; } - *uwidePtr = intValue; } + + /* + * Evil edge case fallback. + */ + + if (GetInvalidIntFromObj(objPtr, &intValue) != TCL_OK) { + return 1; + } + *uwidePtr = intValue; return 0; } |