diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2023-10-01 19:06:33 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2023-10-01 19:06:33 (GMT) |
commit | 9220b96d3c8ec555212d8aee0f81f1c898c75190 (patch) | |
tree | 8723417dca18dfa332b5623378c0b18fe32ce2e8 /generic | |
parent | a568c3a7370ca204923a22917acd5520223036f9 (diff) | |
download | tcl-9220b96d3c8ec555212d8aee0f81f1c898c75190.zip tcl-9220b96d3c8ec555212d8aee0f81f1c898c75190.tar.gz tcl-9220b96d3c8ec555212d8aee0f81f1c898c75190.tar.bz2 |
Fix [7371b6270b]: AddressSanitizer use-after-return detection breaks NRE tests, coroutines. (patch by chrstphrchvz, with some minor modifications)
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclBasic.c | 39 | ||||
-rw-r--r-- | generic/tclInt.decls | 6 | ||||
-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, 14 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 26530c3..096ce20 100644 --- a/generic/tclBasic.c +++ b/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. + */ + +#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 + 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 a/generic/tclInt.decls b/generic/tclInt.decls index ca122f7..993cc5d 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -540,6 +540,11 @@ declare 218 { } # for use in tclTest.c + +# Bug 7371b6270b +declare 223 { + void *TclGetCStackPtr(void) +} declare 224 { TclPlatformType *TclGetPlatform(void) } @@ -586,7 +591,6 @@ declare 235 { void TclInitVarHashTable(TclVarHashTable *tablePtr, Namespace *nsPtr) } - # TIP 337 made this one public declare 236 { void TclBackgroundException(Tcl_Interp *interp, int code) diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index e958733..cb13327 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -532,7 +532,8 @@ EXTERN void TclPopStackFrame(Tcl_Interp *interp); /* Slot 220 is reserved */ /* Slot 221 is reserved */ /* Slot 222 is reserved */ -/* Slot 223 is reserved */ +/* 223 */ +EXTERN void * TclGetCStackPtr(void); /* 224 */ EXTERN TclPlatformType * TclGetPlatform(void); /* 225 */ @@ -875,7 +876,7 @@ typedef struct TclIntStubs { void (*reserved220)(void); void (*reserved221)(void); void (*reserved222)(void); - void (*reserved223)(void); + void * (*tclGetCStackPtr) (void); /* 223 */ TclPlatformType * (*tclGetPlatform) (void); /* 224 */ Tcl_Obj * (*tclTraceDictPath) (Tcl_Interp *interp, Tcl_Obj *rootPtr, int keyc, Tcl_Obj *const keyv[], int flags); /* 225 */ int (*tclObjBeingDeleted) (Tcl_Obj *objPtr); /* 226 */ @@ -1289,7 +1290,8 @@ extern const TclIntStubs *tclIntStubsPtr; /* Slot 220 is reserved */ /* Slot 221 is reserved */ /* Slot 222 is reserved */ -/* 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 9dc3ca0..34bf824 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -720,7 +720,7 @@ static const TclIntStubs tclIntStubs = { 0, /* 220 */ 0, /* 221 */ 0, /* 222 */ - 0, /* 223 */ + TclGetCStackPtr, /* 223 */ TclGetPlatform, /* 224 */ TclTraceDictPath, /* 225 */ TclObjBeingDeleted, /* 226 */ diff --git a/generic/tclTest.c b/generic/tclTest.c index 0061da6..d05ef7d 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -7390,23 +7390,23 @@ NREUnwind_callback( Tcl_Interp *interp, int result) { - int none; + void *cStackPtr = 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) ((char *) 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); |