Tcl Source Code

Artifact [2f6d21b27b]
Login

Artifact 2f6d21b27b641f3cc974255239cdadd2586011fcad504c2b662aad205ec85f6f:

Attachment "7371b6270b.diff" to ticket [7371b6270b] added by chrstphrchvz 2023-09-30 08:36:43.
diff --git generic/tclBasic.c generic/tclBasic.c
index 26530c3924..335c09b91e 100644
--- generic/tclBasic.c
+++ generic/tclBasic.c
@@ -23,7 +23,42 @@
 #include "tommath.h"
 #include <math.h>
 #include <assert.h>
+
+/*
+ * Bug 7371b6270b: to check C call stack depth, prefer an approach which is
+ * compatible with AddressSanitizer (ASan) use-after-return detection.
+ */
 
+#ifdef _MSC_VER
+#include <intrin.h> /* for _AddressOfReturnAddress() */
+#endif
+
+/*
+ * As suggested by
+ * https://clang.llvm.org/docs/LanguageExtensions.html#has-builtin
+ */
+#ifndef __has_builtin
+#define __has_builtin(x) 0 /* for non-clang compilers */
+#endif
+
+void *
+TclGetCStackPtr(void)
+{
+#ifdef _MSC_VER
+  return _AddressOfReturnAddress();
+#elif __GNUC__ || __has_builtin(__builtin_frame_address)
+  return __builtin_frame_address(0);
+#else
+  int unused = 0;
+  /*
+   * LLVM recommends using volatile:
+   * https://github.com/llvm/llvm-project/blob/llvmorg-10.0.0-rc1/clang/lib/Basic/Stack.cpp#L31
+   */
+  int *volatile stackLevel = &unused;
+  return (void *)stackLevel;
+#endif
+}
+
 #define INTERP_STACK_INITIAL_SIZE 2000
 #define CORO_STACK_INITIAL_SIZE    200
 
@@ -8824,8 +8859,8 @@ TclNRCoroutineActivateCallback(
 {
     CoroutineData *corPtr = (CoroutineData *)data[0];
     int type = PTR2INT(data[1]);
-    int numLevels, unused;
-    int *stackLevel = &unused;
+    int numLevels;
+    void *stackLevel = TclGetCStackPtr();
 
     if (!corPtr->stackLevel) {
         /*
diff --git generic/tclInt.decls generic/tclInt.decls
index ca122f7687..a8f86afa8e 100644
--- generic/tclInt.decls
+++ generic/tclInt.decls
@@ -690,7 +690,12 @@ declare 257 {
 	    Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc)
 }
 
-declare 261 {
+# Bug 7371b6270b
+declare 262 {
+    void *TclGetCStackPtr(void)
+}
+
+declare 263 {
     void TclUnusedStubEntry(void)
 }
 
diff --git generic/tclIntDecls.h generic/tclIntDecls.h
index e9587332c8..1782d21fdf 100644
--- generic/tclIntDecls.h
+++ generic/tclIntDecls.h
@@ -645,7 +645,10 @@ EXTERN void		TclStaticPackage(Tcl_Interp *interp,
 /* Slot 258 is reserved */
 /* Slot 259 is reserved */
 /* Slot 260 is reserved */
-/* 261 */
+/* Slot 261 is reserved */
+/* 262 */
+EXTERN void *		TclGetCStackPtr(void);
+/* 263 */
 EXTERN void		TclUnusedStubEntry(void);
 
 typedef struct TclIntStubs {
@@ -913,7 +916,9 @@ typedef struct TclIntStubs {
     void (*reserved258)(void);
     void (*reserved259)(void);
     void (*reserved260)(void);
-    void (*tclUnusedStubEntry) (void); /* 261 */
+    void (*reserved261)(void);
+    void * (*tclGetCStackPtr) (void); /* 262 */
+    void (*tclUnusedStubEntry) (void); /* 263 */
 } TclIntStubs;
 
 extern const TclIntStubs *tclIntStubsPtr;
@@ -1360,8 +1365,11 @@ extern const TclIntStubs *tclIntStubsPtr;
 /* Slot 258 is reserved */
 /* Slot 259 is reserved */
 /* Slot 260 is reserved */
+/* Slot 261 is reserved */
+#define TclGetCStackPtr \
+	(tclIntStubsPtr->tclGetCStackPtr) /* 262 */
 #define TclUnusedStubEntry \
-	(tclIntStubsPtr->tclUnusedStubEntry) /* 261 */
+	(tclIntStubsPtr->tclUnusedStubEntry) /* 263 */
 
 #endif /* defined(USE_TCL_STUBS) */
 
diff --git generic/tclStubInit.c generic/tclStubInit.c
index 9dc3ca0605..01da66b2bc 100644
--- generic/tclStubInit.c
+++ generic/tclStubInit.c
@@ -758,7 +758,9 @@ static const TclIntStubs tclIntStubs = {
     0, /* 258 */
     0, /* 259 */
     0, /* 260 */
-    TclUnusedStubEntry, /* 261 */
+    0, /* 261 */
+    TclGetCStackPtr, /* 262 */
+    TclUnusedStubEntry, /* 263 */
 };
 
 static const TclIntPlatStubs tclIntPlatStubs = {
diff --git generic/tclTest.c generic/tclTest.c
index 0061da6b78..4c523ec964 100644
--- generic/tclTest.c
+++ generic/tclTest.c
@@ -7390,23 +7390,23 @@ NREUnwind_callback(
     Tcl_Interp *interp,
     int result)
 {
-    int none;
+    char *cStackPtr = (char *)TclGetCStackPtr();
     (void)result;
 
     if (data[0] == INT2PTR(-1)) {
-        Tcl_NRAddCallback(interp, NREUnwind_callback, &none, INT2PTR(-1),
+        Tcl_NRAddCallback(interp, NREUnwind_callback, cStackPtr, INT2PTR(-1),
                 INT2PTR(-1), NULL);
     } else if (data[1] == INT2PTR(-1)) {
-        Tcl_NRAddCallback(interp, NREUnwind_callback, data[0], &none,
+        Tcl_NRAddCallback(interp, NREUnwind_callback, data[0], cStackPtr,
                 INT2PTR(-1), NULL);
     } else if (data[2] == INT2PTR(-1)) {
         Tcl_NRAddCallback(interp, NREUnwind_callback, data[0], data[1],
-                &none, NULL);
+                cStackPtr, NULL);
     } else {
         Tcl_Obj *idata[3];
         idata[0] = Tcl_NewIntObj((int) ((char *) data[1] - (char *) data[0]));
         idata[1] = Tcl_NewIntObj((int) ((char *) data[2] - (char *) data[0]));
-        idata[2] = Tcl_NewIntObj((int) ((char *) &none   - (char *) data[0]));
+        idata[2] = Tcl_NewIntObj((int) (cStackPtr        - (char *) data[0]));
         Tcl_SetObjResult(interp, Tcl_NewListObj(3, idata));
     }
     return TCL_OK;
@@ -7452,10 +7452,10 @@ TestNRELevels(
     (void)objv;
 
     if (refDepth == NULL) {
-	refDepth = &depth;
+	refDepth = (ptrdiff_t *)TclGetCStackPtr();
     }
 
-    depth = (refDepth - &depth);
+    depth = (refDepth - (ptrdiff_t *)TclGetCStackPtr());
 
     levels[0] = Tcl_NewIntObj(depth);
     levels[1] = Tcl_NewIntObj(iPtr->numLevels);