Resize of the mp_digit type

In Tcl releases 8.5.0 through 8.5.7, the public header file tcl.h contains the typedef:

typedef unsigned long mp_digit;

Starting in Tcl 8.5.8, this is changed to:

typedef unsigned int mp_digit;

The purpose of this page is to discuss what incompatibilities this may introduce for C code that uses the Tcl public interface, and how to manage them.


First, note that on many (32-bit) systems, long and int are just two names for the same thing. If your C code is only ever compiled on such systems, the change is not really a change at all, and you have no compatibility issues to worry about.

For C code that does get compiled for L64 systems, read on...


The set of public Tcl routines that are affected by this change can only be called from a compilation unit that includes the header file tclTomMath.h in addition to tcl.h. For those C source files that do not include the tclTomMath.h header, there can be no incompatibility in how the Tcl public interface is used introduced by this change.

Having eliminated that possibility, the only remaining thing to check is whether you have your own C code that for some reason contains expressions that operate on variables of type mp_digit. If that is the case, you will need to examine what impact this change has for builds on LP64 systems. Since that situation is unlikely, and has nothing to do with calls into Tcl public routines, we'll say no more about it here.


Compilation units that include tclTomMath.h are presumed to be calling one of the routines declared by it. If your C code calls only those routines with only (mp_int *) arguments, chances are good that the 8.5.7 -> 8.5.8 patch release transition will cause no incompatibility for you. For example, code like this:

#include <tcl.h>
#include <tclTomMath.h>

Tcl_Obj *Multiply(Tcl_Obj *fact1Ptr, Tcl_Obj *fact2Ptr) {
    mp_int a, b, product;

    /* Error checking and handling left out of simplified example */
    Tcl_GetBignumFromObj(NULL, fact1Ptr, &a);
    Tcl_GetBignumFromObj(NULL, fact2Ptr, &b);
    mp_mul(&a, &b, &product);
    mp_clear(&a);
    mp_clear(&b);
    return Tcl_NewBignumObj(&product);
}

is fully source-,binary-, and stubs-compatible across the transition from 8.5.7 headers to 8.5.8 headers. Binary code produced from compiling against either side of the header transition can be loaded in or dynamically linked to a Tcl library compiled against headers either side of the transition, and run correctly.

The exception is any circumstance where your own code operates on the dp array of some mp_int value. If that happens, you must be sure the binaries compiled from your code are properly match to the binaries of the Tcl library that agree on the size of the mp_digit type.


On the other hand, if your C code calls any of the routines with either mp_digit or (mp_digit *) arguments:

  mp_add_d()
  mp_cmp_d()
  mp_div_d()
  mp_expt_d()
  mp_init_set()
  mp_mul_d()
  mp_set()
  mp_sub_d()

Then your code does have a binary and stubs incompatibility with Tcl at the 8.5.7 -> 8.5.8 patch release transition. The change in size of the mp_digit type on LP64 systems means that binary code produced assuming one size will be incompatible with binary code produced assuming the other size.


If you do have code that suffers from this incompatibility, the simplest way to deal with it is to treat Tcl releases 8.5.0 through 8.5.7 as buggy and move immediately to requiring Tcl 8.5.8 as the minimum version your code can work with.

If that is too abrupt a break to force onto users of your code, we can sketch out more complex, robust, and gentle migration plans here, if necessary.

When we approved this change as something to permit in a patchlevel release even with this potential for incompatibility, we believed any code facing the incompatibility would be rare, and possibly nonexistent. In light of that, I'll save any discussion of more complex migration plans until I hear of actual problems arising from the issue.

Thanks for reading!