diff options
-rw-r--r-- | generic/tclBasic.c | 40 | ||||
-rw-r--r-- | generic/tclInt.decls | 4 | ||||
-rw-r--r-- | generic/tclIntDecls.h | 8 | ||||
-rw-r--r-- | generic/tclStubInit.c | 2 | ||||
-rw-r--r-- | generic/tclTest.c | 14 |
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); |