summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclBasic.c40
-rw-r--r--generic/tclInt.decls4
-rw-r--r--generic/tclIntDecls.h8
-rw-r--r--generic/tclStubInit.c2
-rw-r--r--generic/tclTest.c14
5 files changed, 55 insertions, 13 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index 318374e..4187462 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -64,6 +64,41 @@
#endif /* !TCL_FPCLASSIFY_MODE */
+/*
+ * Bug 7371b6270b: to check C call stack depth, prefer an approach which is
+ * compatible with AddressSanitizer (ASan) use-after-return detection.
+ */
+
+#if defined(HAVE_INTRIN_H)
+#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)
+{
+#if defined(HAVE_INTRIN_H)
+ return _AddressOfReturnAddress();
+#elif __GNUC__ || __has_builtin(__builtin_frame_address)
+ return __builtin_frame_address(0);
+#else
+ ptrdiff_t unused = 0;
+ /*
+ * LLVM recommends using volatile:
+ * https://github.com/llvm/llvm-project/blob/llvmorg-10.0.0-rc1/clang/lib/Basic/Stack.cpp#L31
+ */
+ ptrdiff_t *volatile stackLevel = &unused;
+ return (void *)stackLevel;
+#endif
+}
+
#define INTERP_STACK_INITIAL_SIZE 2000
#define CORO_STACK_INITIAL_SIZE 200
@@ -9726,6 +9761,7 @@ TclNRCoroutineActivateCallback(
TCL_UNUSED(int) /*result*/)
{
CoroutineData *corPtr = (CoroutineData *)data[0];
+ void *stackLevel = TclGetCStackPtr();
if (!corPtr->stackLevel) {
/*
@@ -9742,7 +9778,7 @@ TclNRCoroutineActivateCallback(
* the interp's environment to make it suitable to run this coroutine.
*/
- corPtr->stackLevel = &corPtr;
+ corPtr->stackLevel = stackLevel;
Tcl_Size numLevels = corPtr->auxNumLevels;
corPtr->auxNumLevels = iPtr->numLevels;
@@ -9756,7 +9792,7 @@ TclNRCoroutineActivateCallback(
* Coroutine is active: yield
*/
- if (corPtr->stackLevel != &corPtr) {
+ if (corPtr->stackLevel != stackLevel) {
NRE_callback *runPtr;
iPtr->execEnvPtr = corPtr->callerEEPtr;
diff --git a/generic/tclInt.decls b/generic/tclInt.decls
index 15d2cfa..218df69 100644
--- a/generic/tclInt.decls
+++ b/generic/tclInt.decls
@@ -546,6 +546,10 @@ declare 221 {
declare 222 {
void TclListObjValidate(Tcl_Interp *interp, Tcl_Obj *listObj)
}
+# Bug 7371b6270b
+declare 223 {
+ void *TclGetCStackPtr(void)
+}
declare 224 {
TclPlatformType *TclGetPlatform(void)
}
diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h
index d8f3af8..a72f615 100644
--- a/generic/tclIntDecls.h
+++ b/generic/tclIntDecls.h
@@ -552,7 +552,8 @@ EXTERN Tcl_Obj * TclListTestObj(size_t length, size_t leadingSpace,
/* 222 */
EXTERN void TclListObjValidate(Tcl_Interp *interp,
Tcl_Obj *listObj);
-/* Slot 223 is reserved */
+/* 223 */
+EXTERN void * TclGetCStackPtr(void);
/* 224 */
EXTERN TclPlatformType * TclGetPlatform(void);
/* 225 */
@@ -895,7 +896,7 @@ typedef struct TclIntStubs {
void (*reserved220)(void);
Tcl_Obj * (*tclListTestObj) (size_t length, size_t leadingSpace, size_t endSpace); /* 221 */
void (*tclListObjValidate) (Tcl_Interp *interp, Tcl_Obj *listObj); /* 222 */
- void (*reserved223)(void);
+ void * (*tclGetCStackPtr) (void); /* 223 */
TclPlatformType * (*tclGetPlatform) (void); /* 224 */
Tcl_Obj * (*tclTraceDictPath) (Tcl_Interp *interp, Tcl_Obj *rootPtr, Tcl_Size keyc, Tcl_Obj *const keyv[], int flags); /* 225 */
int (*tclObjBeingDeleted) (Tcl_Obj *objPtr); /* 226 */
@@ -1312,7 +1313,8 @@ extern const TclIntStubs *tclIntStubsPtr;
(tclIntStubsPtr->tclListTestObj) /* 221 */
#define TclListObjValidate \
(tclIntStubsPtr->tclListObjValidate) /* 222 */
-/* Slot 223 is reserved */
+#define TclGetCStackPtr \
+ (tclIntStubsPtr->tclGetCStackPtr) /* 223 */
#define TclGetPlatform \
(tclIntStubsPtr->tclGetPlatform) /* 224 */
#define TclTraceDictPath \
diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c
index dfe25c5..97f37b0 100644
--- a/generic/tclStubInit.c
+++ b/generic/tclStubInit.c
@@ -1003,7 +1003,7 @@ static const TclIntStubs tclIntStubs = {
0, /* 220 */
TclListTestObj, /* 221 */
TclListObjValidate, /* 222 */
- 0, /* 223 */
+ TclGetCStackPtr, /* 223 */
TclGetPlatform, /* 224 */
TclTraceDictPath, /* 225 */
TclObjBeingDeleted, /* 226 */
diff --git a/generic/tclTest.c b/generic/tclTest.c
index ab2e459..2986b19 100644
--- a/generic/tclTest.c
+++ b/generic/tclTest.c
@@ -8038,22 +8038,22 @@ NREUnwind_callback(
Tcl_Interp *interp,
TCL_UNUSED(int) /*result*/)
{
- int none;
+ void *cStackPtr = TclGetCStackPtr();
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_NewWideIntObj(((char *) data[1] - (char *) data[0]));
idata[1] = Tcl_NewWideIntObj(((char *) data[2] - (char *) data[0]));
- idata[2] = Tcl_NewWideIntObj(((char *) &none - (char *) data[0]));
+ idata[2] = Tcl_NewWideIntObj(((char *) cStackPtr - (char *) data[0]));
Tcl_SetObjResult(interp, Tcl_NewListObj(3, idata));
}
return TCL_OK;
@@ -8092,10 +8092,10 @@ TestNRELevels(
NRE_callback *cbPtr = iPtr->execEnvPtr->callbackPtr;
if (refDepth == NULL) {
- refDepth = &depth;
+ refDepth = (ptrdiff_t *)TclGetCStackPtr();
}
- depth = (refDepth - &depth);
+ depth = (refDepth - (ptrdiff_t *)TclGetCStackPtr());
levels[0] = Tcl_NewWideIntObj(depth);
levels[1] = Tcl_NewWideIntObj(iPtr->numLevels);