Ticket UUID: | 5c3679820afa2aca58ef3bb2041181669fab5ac7 | |||
Title: | 64-Bit Extensions Do Not Work With Old Tcl Applications | |||
Type: | Bug | Version: | 9.0.1 | |
Submitter: | anonymous | Created on: | 2025-02-26 18:08:24 | |
Subsystem: | 38. Init - Library - Autoload | Assigned To: | jan.nijtmans | |
Priority: | 5 Medium | Severity: | Minor | |
Status: | Closed | Last Modified: | 2025-03-03 15:03:23 | |
Resolution: | Invalid | Closed By: | jan.nijtmans | |
Closed on: | 2025-03-03 15:03:23 | |||
Description: |
Tcl extensions created as shared library via stubs interface do not work with old 64-bit tcl applications (version < 9). Reason: Function / Macro Tcl_InitStubs: In case of 64-bit application, the application calls Tcl_InitStubs with interface pointer containing a TclStubs pointer with field magic = 0xFCA3BACF. Unfortunately, since Tcl_InitStubs is a macro, parameter magic becomes 0xFCA3BAD3 and exact becomes (exact|0xff0900). The result is that TclStubs field magic does not equals parameter magic, therefore the function fails always. Correct behaviour should be: If parameter version specifies any version < 9, the function should not fail if TclStubs field magic equals either magic or 0xFCA3BACF. | |||
User Comments: |
jan.nijtmans added on 2025-03-03 15:03:23:
Marking ticket as "Invalid", as there is no binary compatibility between Tcl 8.6 and 9.0. This was never a design goal. jan.nijtmans added on 2025-03-03 15:00:43: > Is it really correct that only the 64 bit applications (version 8 and 9) are binary incompatible and the 32 bit applications remain binary compatible? First question: Yes! For example, try: Tcl_Obj *obj = Tcl_NewStringObj("hello", -1); printf(obj->bytes);If you do this in a 64-bit Tcl-8.6-compiled extension, running in Tcl 9.0. the second argument of Tcl_NewStringObj() is a "int", so the value 0xFFFFFFFF (4 bytes) will be pushed on stack. Tcl9.0 will pull 8 bytes off the stack, which will be 4 0xFF bytes followed by 4 bytes of random data. That will crash, unless .... modern compilers don't use the stack for such function parameters but internal registers. That will work. Phew, you are lucky. Then, the obj->bytes field is just after the obj->refCount field, which is 4 bytes in Tcl 8.6 and 8 bytes in Tcl 9.0. Since most compilers align the obj->bytes fields on a multiple of 8 bytes, you are lucky again: it will work. But - you see - you cannot depend on that. More complicated examples will certainly crash. You will be on your own trying that, that's why the magic value was changed. On 32-bit machines, it will be almost binary compatible. There are 2 things you cannot do: * Call any of the deprecated functions, like Tcl_MakeSafe(). They only work in Tcl 8.6 * Call any of the internal functions (in tclIntDecls.h), they moved to different stub entries Since there is no way to know if an already-compiled extension voilates that, I don't recommend running a Tcl 8.6 extension in Tcl 9.0 or reverse. If it works, you are lucky. Better recompile it in a Tcl 9.0 environment, then the compiler should complain if there is a problem. anonymous added on 2025-03-02 22:25:08: Yes, there are some incompatibilities, e.g. channel handling and Unicode, and it will be necessary to recompile the extension. Setting major no. to 8 works well and calling TclInitStubs with version 8.1 will bind it to old tcl apps and with version 9.0 to new ones. I tried it with 32 bit tcl apps (8.6 and 9.0) and it worked well (udptcl extension with little changes). What I see is that there is a difference between 32 bit and 64 bit handling: For 32 bit extensions, it works as described because magics for version 8 and 9 are the same. For 64 bit extensions, it does not work because TclInitStubs accepts only one magic: Either 0xFCA3BACF, if compiled for old tcl apps (in this case, recompile would not be necessar4y) or 0xFCA3BAD3, if compiled for new tcl apps with major version = 9. Is it really correct that only the 64 bit applications (version 8 and 9) are binary incompatible and the 32 bit applications remain binary compatible? Or is it an error that magic has only been changed for 64 bit versions? Do you have an example for a function or structure where old and new 64 bit tcl apps are binary incompatibility, but old and new tcl apps remain binary compatible? jan.nijtmans added on 2025-02-26 19:36:06: This is intentional. Tcl 9 is not binary compatible with Tcl 8, so your old extensions need to recompiled. The magic for Tcl 8.x is 0xFCA3BAD3, the magic for Tcl 9.x (64-bit) is 0xFCA3BACF. This is done on purpose, to assure that you cannot accidently load a Tcl8-compiled extensions in a Tcl9 application or reverse. The Tcl 9 headers allow to compile for Tcl8, if you compile with -DTCL_MAJOR_VERSION=8. The magic then automatically changes to 0xFCA3BAD3. Hope this helps, Jan Nijtmans |
