Tcl Source Code

Ticket Change Details
Login
Overview

Artifact ID: 0d3171c42f1ff28b3ba3b98967e4e04bbfbec707
Ticket: 2089279fffffffffffffffffffffffffffffffff
StringObj.3 Tcl_ObjPrintf inaccuracies
User & Date: stu 2017-07-08 18:37:03
Changes

  1. closer changed to: "nobody"
  2. 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.
    
  3. 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.
    
  4. login: "stu"
  5. mimetype: "text/plain"
  6. severity changed to: "Minor"