Overview
Artifact ID: | 0d3171c42f1ff28b3ba3b98967e4e04bbfbec707 |
---|---|
Ticket: | 2089279fffffffffffffffffffffffffffffffff
StringObj.3 Tcl_ObjPrintf inaccuracies |
User & Date: | stu 2017-07-08 18:37:03 |
Changes
- closer changed to: "nobody"
- comment changed to:
StringObj.3 gives this example: long x = 5; Tcl_Obj *objPtr = Tcl_ObjPrintf("Value is %d", x); This is incorrect, because the Tcl_ObjPrintf code will expect an int, and use va_arg with int. As can be seen in the AppendPrintfToObjVA: case 'd': ... seekingConversion = 0; switch (size) { case -1: case 0: Tcl_ListObjAppendElement(NULL, list, Tcl_NewLongObj((long int)va_arg(argList, int))); The issue is that if the user uses %d for a long, the va_list will have the wrong offset. The example will work in the 1 argument case, and even the multiple argument case if sizeof(int) = sizeof(long). It however will fail in the case of sizeof(long) > sizeof(int), because the va_list will have the wrong offset. Thus you'd be getting parts of the integer. This can have disasterous consequences if the offset is wrong, because the next va_arg call becomes wrong, which if it's a pointer may lead to segfaults. Tcl works with some platforms where a long is 64-bit and an int is 32-bit. #ifdef TCL_WIDE_INT_IS_LONG as I understand it refers to this. The next issue is that the format specifiers are not exactly the same as the [format] command, and probably shouldn't be. The format command uses (as documented) %ld for truncation to a 64-bit integer. %lld for no truncation (BigNum) and %d for a 32-bit integer. This is incomptible with AppendPrintfToObjVA() (used by Tcl_ObjPrintf), because it currently accepts a long for %ld which may or may not be 64-bit depending on the platform. The wide and BigNum cases are also not handled by AppendPrintfToObjVA(). Thus the suggestion in the documentation that Tcl_ObjPrintf has the same syntax as the format command are wrong.
- icomment:
Just stumbled across this. See also http://core.tcl.tk/tcl/tktview/2b6a4fa5ed30b44364b1 On 32-bit systems: Tcl_ObjPrintf("%lld %ld\n", (long long) 3, (long) 4)) Yields "3 0" Tcl_ObjPrintf("%lld %s\n", (long long) 3, "a")) Segfaults Right now it's hard to have confidence in Tcl_ObjPrintf. Even if it was fixed today the broken version will persist in the wild for a long time possibly requiring autoconfery for those who wish to use it with confidence. Too bad.
- login: "stu"
- mimetype: "text/plain"
- severity changed to: "Minor"