Skip to content

Tkinter: incompatible pointer types warnings when built with Tcl 9 #112672

Description

@chrstphrchvz

Tcl/Tk 9 changes C APIs to use a different type for sizes to allow transferring ≥32-bit sized things. The new type is Tcl_Size, which as of TIP 660 is defined as either ptrdiff_t in Tcl 9, or int in Tcl 8.7 for binary compatibility.

My impression is that Tcl/Tk wrappers such as Tkinter, which are primarily used for Tk GUI, have little if any need for this. But as of TIP 664, usage of APIs which previously expected int * must be updated for Tcl 9. There was previously effort in Tcl to continue allowing int * usage for compatibility, and maybe that would have been good enough for Tkinter, but others in the Tcl/Tk inner circle (who already wish to abandon Tcl/Tk < 9 entirely) rejected that approach. -Wincompatible-pointer-types warnings now seen under Tcl 9:

./Modules/_tkinter.c:504:21: warning: incompatible pointer types passing 'int *' to parameter of type 'Tcl_Size *' (aka 'long *') [-Wincompatible-pointer-types]
  504 |     const char *s = Tcl_GetStringFromObj(value, &len);
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tcl90/include/tclDecls.h:4235:36: note: expanded from macro 'Tcl_GetStringFromObj'
 4235 |                 (Tcl_GetStringFromObj)((objPtr), (sizePtr)))
      |                                                  ^~~~~~~~~
tcl90/include/tclDecls.h:1754:15: note: passing argument to parameter 'lengthPtr' here
 1754 |                                 Tcl_Size *lengthPtr);
      |                                           ^
./Modules/_tkinter.c:1138:29: warning: incompatible pointer types passing 'int *' to parameter of type 'Tcl_Size *' (aka 'long *') [-Wincompatible-pointer-types]
 1138 |         char *data = (char*)Tcl_GetByteArrayFromObj(value, &size);
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tcl90/include/tclDecls.h:4229:41: note: expanded from macro 'Tcl_GetByteArrayFromObj'
 4229 |                 (Tcl_GetBytesFromObj)(NULL, (objPtr), (sizePtr)))
      |                                                       ^~~~~~~~~
tcl90/include/tclDecls.h:1751:32: note: passing argument to parameter 'numBytesPtr' here
 1751 |                                 Tcl_Obj *objPtr, Tcl_Size *numBytesPtr);
      |                                                            ^
./Modules/_tkinter.c:1168:18: warning: incompatible pointer types passing 'int *' to parameter of type 'Tcl_Size *' (aka 'long *') [-Wincompatible-pointer-types]
 1168 |         status = Tcl_ListObjLength(interp, value, &size);
      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tcl90/include/tclDecls.h:4244:44: note: expanded from macro 'Tcl_ListObjLength'
 4244 |                 (Tcl_ListObjLength)((interp), (listPtr), (lengthPtr)))
      |                                                          ^~~~~~~~~~~
tcl90/include/tclDecls.h:1790:33: note: passing argument to parameter 'lengthPtr' here
 1790 |                                 Tcl_Obj *listPtr, Tcl_Size *lengthPtr);
      |                                                             ^
./Modules/_tkinter.c:2104:13: warning: incompatible pointer types passing 'int *' to parameter of type 'Tcl_Size *' (aka 'long *') [-Wincompatible-pointer-types]
 2104 |         if (Tcl_ListObjGetElements(Tkapp_Interp(self),
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2105 |                                    ((PyTclObject*)arg)->value,
      |                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2106 |                                    &objc, &objv) == TCL_ERROR) {
      |                                    ~~~~~~~~~~~~~
tcl90/include/tclDecls.h:4241:49: note: expanded from macro 'Tcl_ListObjGetElements'
 4241 |                 (Tcl_ListObjGetElements)((interp), (listPtr), (objcPtr), (objvPtr)))
      |                                                               ^~~~~~~~~
tcl90/include/tclDecls.h:1786:33: note: passing argument to parameter 'objcPtr' here
 1786 |                                 Tcl_Obj *listPtr, Tcl_Size *objcPtr,
      |                                                             ^
./Modules/_tkinter.c:2136:9: warning: incompatible pointer types passing 'int *' to parameter of type 'Tcl_Size *' (aka 'long *') [-Wincompatible-pointer-types]
 2136 |     if (Tcl_SplitList(Tkapp_Interp(self), list,
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2137 |                       &argc, &argv) == TCL_ERROR)  {
      |                       ~~~~~~~~~~~~~
tcl90/include/tclDecls.h:4250:40: note: expanded from macro 'Tcl_SplitList'
 4250 |                 (Tcl_SplitList)((interp), (listStr), (argcPtr), (argvPtr)))
      |                                                      ^~~~~~~~~
tcl90/include/tclDecls.h:1796:36: note: passing argument to parameter 'argcPtr' here
 1796 |                                 const char *listStr, Tcl_Size *argcPtr,
      |                                                                ^
5 warnings generated.

Code intending to remain compatible with Tcl 8.6 is suggested to use the following after including tcl.h:

#ifndef TCL_SIZE_MAX
typedef int Tcl_Size;
# define Tcl_GetSizeIntFromObj Tcl_GetIntFromObj
# define Tcl_NewSizeIntObj Tcl_NewIntObj
# define TCL_SIZE_MAX      INT_MAX
# define TCL_SIZE_MODIFIER ""
#endif

I intend to open a PR updating _tkinter.c to pass Tcl_Size * where needed.

There are several other instances where Tkinter assumes Tcl expectsint or something not larger than INT_MAX, but migrating those to Tcl_Size and TCL_SIZE_MAX seems optional.

Linked PRs

Activity

  1. chrstphrchvz commented on Dec 8, 2023

    @chrstphrchvz
    ContributorAuthor

    Code intending to remain compatible with Tcl 8.6 is suggested to use the following after including tcl.h:

    #ifndef TCL_SIZE_MAX
    typedef int Tcl_Size;
    # define Tcl_GetSizeIntFromObj Tcl_GetIntFromObj
    # define Tcl_NewSizeIntObj Tcl_NewIntObj
    # define TCL_SIZE_MAX      INT_MAX
    # define TCL_SIZE_MODIFIER ""
    #endif
    

    There is ongoing debate upstream about what is actually needed here, most recently in https://sourceforge.net/p/tcl/mailman/tcl-core/thread/74564788-7d69-4c42-9205-c5f3e6a1409d%40elmicron.de/
    Some want Tcl_Size to be a macro and not a typedef. Some do not want to force downstream projects/users to need “boilerplate” for 8.6 compatibility. Others do not care about Tcl/Tk < 9.0 and will gladly pass the buck downstream.

  2. added a commit that references this issue on Jun 4, 2024
  3. serhiy-storchaka commented on Jun 4, 2024

    @serhiy-storchaka
    Member

    In future we may change more code to support longer data in Python->Tcl conversion. But this requires testing, because not always the library supports larger than 2GiB data even if the size type is 64-bit (for example SQLite has 32-bit limitation even in its 64-bit API),

  4. added a commit that references this issue on Jun 5, 2024
  5. added a commit that references this issue on Jun 7, 2024
  6. added a commit that references this issue on Jun 7, 2024
  7. added 2 commits that reference this issue on Jun 7, 2024
  8. added a commit that references this issue on Jul 11, 2024
  9. added a commit that references this issue on Jul 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

3.12only security fixes3.13only security fixes3.14bugs and security fixestopic-tkinter

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions