From 8648d41bfdf5c47c3f6fdf98333def73542c6ec8 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 3 Jan 2025 15:47:14 +0000 Subject: [PATCH 1/3] Proposed fix for [fc35093ce]: Better error-message than "interpreter uses an incompatible stubs mechanism" --- generic/tclLoad.c | 7 +++---- generic/tclStubLib.c | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/generic/tclLoad.c b/generic/tclLoad.c index 95f9c223495e..96691cc6a43a 100644 --- a/generic/tclLoad.c +++ b/generic/tclLoad.c @@ -482,11 +482,10 @@ Tcl_LoadObjCmd( Interp *iPtr = (Interp *) target; if (iPtr->legacyResult && *(iPtr->legacyResult) && !iPtr->legacyFreeProc) { /* - * A call to Tcl_InitStubs() determined the caller extension and - * this interp are incompatible in their stubs mechanisms, and - * recorded the error in the oldest legacy place we have to do so. + * A call to Tcl_InitStubs() determined the caller extension + * Stubs were introduced in Tcl 8.1, so there's only one possible reason. */ - Tcl_SetObjResult(target, Tcl_NewStringObj(iPtr->legacyResult, -1)); + Tcl_SetObjResult(target, Tcl_NewStringObj("this extension is compiled for Tcl 8.x", -1)); iPtr->legacyResult = NULL; iPtr->legacyFreeProc = (void (*) (void))-1; } diff --git a/generic/tclStubLib.c b/generic/tclStubLib.c index 55001cf8a38b..e5ac43629201 100644 --- a/generic/tclStubLib.c +++ b/generic/tclStubLib.c @@ -60,19 +60,26 @@ Tcl_InitStubs( const char *actualVersion = NULL; void *pkgData = NULL; const TclStubs *stubsPtr = iPtr->stubTable; - const char *tclName = (((exact&0xFF00) >= 0x900) ? "tcl" : "Tcl"); + const char *tclName = "tcl"; -#undef TCL_STUB_MAGIC /* We need the TCL_STUB_MAGIC from Tcl 8.x here */ -#define TCL_STUB_MAGIC ((int) 0xFCA3BACF) + if ((exact&0xFF00) < 0x900) { + magic = (int) 0xFCA3BACF; /* TCL_STUB_MAGIC from Tcl 8.x */ + tclName = "Tcl"; + } /* * We can't optimize this check by caching tclStubsPtr because that * prevents apps from being able to load/unload Tcl dynamically multiple * times. [Bug 615304] */ - if (!stubsPtr || (stubsPtr->magic != (((exact&0xFF00) >= 0x900) ? magic : TCL_STUB_MAGIC))) { - iPtr->legacyResult = "interpreter uses an incompatible stubs mechanism"; - iPtr->legacyFreeProc = 0; /* TCL_STATIC */ + if (!stubsPtr || (stubsPtr->magic != magic)) { + if (((exact&0xFF00) >= 0x900) && stubsPtr && (stubsPtr->magic == TCL_STUB_MAGIC)) { + stubsPtr->tcl_SetObjResult(interp, stubsPtr->tcl_ObjPrintf("this extension is compiled for Tcl %d.%d", + (exact&0xFF00)>>8, (exact&0xFF0000)>>16)); + } else { + iPtr->legacyResult = "interpreter uses an incompatible stubs mechanism"; + iPtr->legacyFreeProc = 0; /* TCL_STATIC */ + } return NULL; } From 571b1d50131cc7acf4874616a5ee3169553fe23b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 6 Jan 2025 17:10:30 +0000 Subject: [PATCH 2/3] Fix [fc35093ce] for Tcl 8.6: Better error-message than "interpreter uses an incompatible stubs mechanism". Minor doc fix. --- changes | 2 ++ doc/InitStubs.3 | 2 +- generic/tclStubLib.c | 18 +++++++++++++++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/changes b/changes index e51771cd4724..3f2c0d3ab241 100644 --- a/changes +++ b/changes @@ -9384,3 +9384,5 @@ Many code fixes to avoid overflow or undefined behavior. Thanks chrstphrchvz. - Released 8.6.16, Dec 11, 2024 - details at https://core.tcl-lang.org/tcl/ - 2024-12-16 (bug) [63449c] [namespace children] doesn't match non-glob patterns below the global namespace (stu) + +2025-01-06 (bug) [63449c] Better error-message than "interpreter uses an incompatible stubs mechanism" (nijtmans) diff --git a/doc/InitStubs.3 b/doc/InitStubs.3 index fbb3f5601073..c53caf30b410 100644 --- a/doc/InitStubs.3 +++ b/doc/InitStubs.3 @@ -79,7 +79,7 @@ and a Boolean flag indicating whether the extension requires an exact version match or not. If \fIexact\fR is 0, then the extension is indicating that newer versions of Tcl are acceptable as long as they have the same major version number as \fIversion\fR; -non-zero means that only the specified \fIversion\fR is acceptable. +1 means that only the specified \fIversion\fR is acceptable. \fBTcl_InitStubs\fR returns a string containing the actual version of Tcl satisfying the request, or NULL if the Tcl version is not acceptable, does not support stubs, or any other error condition occurred. diff --git a/generic/tclStubLib.c b/generic/tclStubLib.c index deb622951c11..7bd6109d0c77 100644 --- a/generic/tclStubLib.c +++ b/generic/tclStubLib.c @@ -65,8 +65,20 @@ Tcl_InitStubs( */ if (!stubsPtr || (stubsPtr->magic != TCL_STUB_MAGIC)) { - iPtr->result = (char *)"interpreter uses an incompatible stubs mechanism"; - iPtr->freeProc = TCL_STATIC; + exact &= 0xFFFF00; /* Filter out minor/major Tcl version */ + if (!exact) { + exact = 0x060800; + } + if (stubsPtr && (stubsPtr->magic == ((int)0xFCA3BACB + (int)sizeof(void *))) + && ((exact|0x010000) == 0x070800)) { + /* We are running in Tcl 9.x, but extension is compiled with 8.6 or 8.7 */ + stubsPtr->tcl_SetObjResult(interp, stubsPtr->tcl_ObjPrintf( + "this extension is compiled for Tcl %d.%d", + (exact & 0x0FF00)>>8, (exact & 0x0FF0000)>>16)); + } else { + iPtr->result = (char *)"interpreter uses an incompatible stubs mechanism"; + iPtr->freeProc = TCL_STATIC; + } return NULL; } @@ -74,7 +86,7 @@ Tcl_InitStubs( if (actualVersion == NULL) { return NULL; } - if (exact) { + if (exact&1) { const char *p = version; int count = 0; From e4949db6663a2836024535f4b7f2387ee5f06f67 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 7 Jan 2025 09:19:59 +0000 Subject: [PATCH 3/3] Handle 9.0-compiled extension running in 8.x as well --- generic/tclStubLib.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/generic/tclStubLib.c b/generic/tclStubLib.c index e5ac43629201..7c551c3bfa12 100644 --- a/generic/tclStubLib.c +++ b/generic/tclStubLib.c @@ -63,7 +63,7 @@ Tcl_InitStubs( const char *tclName = "tcl"; if ((exact&0xFF00) < 0x900) { - magic = (int) 0xFCA3BACF; /* TCL_STUB_MAGIC from Tcl 8.x */ + magic = (int)0xFCA3BACF; /* TCL_STUB_MAGIC from Tcl 8.x */ tclName = "Tcl"; } /* @@ -73,9 +73,24 @@ Tcl_InitStubs( */ if (!stubsPtr || (stubsPtr->magic != magic)) { - if (((exact&0xFF00) >= 0x900) && stubsPtr && (stubsPtr->magic == TCL_STUB_MAGIC)) { - stubsPtr->tcl_SetObjResult(interp, stubsPtr->tcl_ObjPrintf("this extension is compiled for Tcl %d.%d", - (exact&0xFF00)>>8, (exact&0xFF0000)>>16)); + exact &= 0xFFFF00; /* Filter out minor/major Tcl version */ + if (!exact) { + exact = 0x060800; + } + if (stubsPtr && (stubsPtr->magic == TCL_STUB_MAGIC) + && ((exact|0x010000) == 0x070800)) { + /* We are running in Tcl 9.x, but extension is compiled with 8.6 or 8.7 */ + stubsPtr->tcl_SetObjResult(interp, stubsPtr->tcl_ObjPrintf( + "this extension is compiled for Tcl %d.%d", + (exact & 0x0FF00)>>8, (exact & 0x0FF0000)>>16)); + } else if (stubsPtr && (stubsPtr->magic == (int)0xFCA3BACF) + && ((exact & 0x0FF00) >= 0x0900)) { + char major[4], minor[4]; + snprintf(major, sizeof(major), "%d", (exact & 0xFF00)>>8); + snprintf(minor, sizeof(minor), "%d", (exact & 0xFF0000)>>16); + /* We are running in Tcl 8.x, but extension is compiled with 9.0+ */ + stubsPtr->tcl_AppendResult(interp, + "this extension is compiled for Tcl ", major, ".", minor, (char *)NULL); } else { iPtr->legacyResult = "interpreter uses an incompatible stubs mechanism"; iPtr->legacyFreeProc = 0; /* TCL_STATIC */