gh-128421: Avoid TSAN warnings in `sys._current_frames()` (gh-131548) · python/cpython@da6730c

GitHub

Original file line numberDiff line numberDiff line change@@ -189,8 +189,11 @@ _PyFrame_SetStackPointer(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer)

189189 * Frames on the frame stack are incomplete until the

190190 * first RESUME instruction.

191191 * Frames owned by a generator are always complete.

192+ *

193+ * NOTE: We allow racy accesses to the instruction pointer

194+ * from other threads for sys._current_frames() and similar APIs.

192195 */

193-staticinlinebool

196+staticinlinebool_Py_NO_SANITIZE_THREAD

194197_PyFrame_IsIncomplete(_PyInterpreterFrame*frame)

195198{

196199if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) {

Original file line numberDiff line numberDiff line change@@ -565,27 +565,45 @@ extern "C" {

565565# if __has_feature(memory_sanitizer)

566566# if !defined(_Py_MEMORY_SANITIZER)

567567# define_Py_MEMORY_SANITIZER

568+# define_Py_NO_SANITIZE_MEMORY__attribute__((no_sanitize_memory))

568569# endif

569570# endif

570571# if __has_feature(address_sanitizer)

571572# if !defined(_Py_ADDRESS_SANITIZER)

572573# define_Py_ADDRESS_SANITIZER

574+# define_Py_NO_SANITIZE_ADDRESS__attribute__((no_sanitize_address))

573575# endif

574576# endif

575577# if __has_feature(thread_sanitizer)

576578# if !defined(_Py_THREAD_SANITIZER)

577579# define_Py_THREAD_SANITIZER

580+# define_Py_NO_SANITIZE_THREAD__attribute__((no_sanitize_thread))

578581# endif

579582# endif

580583#elif defined(__GNUC__)

581584# if defined(__SANITIZE_ADDRESS__)

582585# define_Py_ADDRESS_SANITIZER

586+# define_Py_NO_SANITIZE_ADDRESS__attribute__((no_sanitize_address))

583587# endif

584588# if defined(__SANITIZE_THREAD__)

585589# define_Py_THREAD_SANITIZER

590+# define_Py_NO_SANITIZE_THREAD__attribute__((no_sanitize_thread))

591+# elif __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)

592+// TSAN is supported since GCC 5.1, but __SANITIZE_THREAD__ macro

593+// is provided only since GCC 7.

594+# define_Py_NO_SANITIZE_THREAD__attribute__((no_sanitize_thread))

586595# endif

587596#endif

588597598+#ifndef _Py_NO_SANITIZE_ADDRESS

599+# define_Py_NO_SANITIZE_ADDRESS

600+#endif

601+#ifndef _Py_NO_SANITIZE_THREAD

602+# define_Py_NO_SANITIZE_THREAD

603+#endif

604+#ifndef _Py_NO_SANITIZE_MEMORY

605+# define_Py_NO_SANITIZE_MEMORY

606+#endif

589607590608/* AIX has __bool__ redefined in it's system header file. */

591609#if defined(_AIX) && defined(__bool__)

Original file line numberDiff line numberDiff line change@@ -470,40 +470,6 @@ _PyMem_ArenaFree(void *Py_UNUSED(ctx), void *ptr,

470470/*******************************************/

471471472472473-#if defined(__has_feature) /* Clang */

474-# if__has_feature(address_sanitizer) /* is ASAN enabled? */

475-# define_Py_NO_SANITIZE_ADDRESS \

476- __attribute__((no_sanitize("address")))

477-# endif

478-# if__has_feature(thread_sanitizer) /* is TSAN enabled? */

479-# define_Py_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))

480-# endif

481-# if__has_feature(memory_sanitizer) /* is MSAN enabled? */

482-# define_Py_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))

483-# endif

484-#elif defined(__GNUC__)

485-# if defined(__SANITIZE_ADDRESS__) /* GCC 4.8+, is ASAN enabled? */

486-# define_Py_NO_SANITIZE_ADDRESS \

487- __attribute__((no_sanitize_address))

488-# endif

489-// TSAN is supported since GCC 5.1, but __SANITIZE_THREAD__ macro

490-// is provided only since GCC 7.

491-# if__GNUC__>5|| (__GNUC__==5&&__GNUC_MINOR__ >= 1)

492-# define_Py_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))

493-# endif

494-#endif

495-496-#ifndef_Py_NO_SANITIZE_ADDRESS

497-# define_Py_NO_SANITIZE_ADDRESS

498-#endif

499-#ifndef_Py_NO_SANITIZE_THREAD

500-# define_Py_NO_SANITIZE_THREAD

501-#endif

502-#ifndef_Py_NO_SANITIZE_MEMORY

503-# define_Py_NO_SANITIZE_MEMORY

504-#endif

505-506-507473#defineALLOCATORS_MUTEX (_PyRuntime.allocators.mutex)

508474#define_PyMem_Raw (_PyRuntime.allocators.standard.raw)

509475#define_PyMem (_PyRuntime.allocators.standard.mem)

Original file line numberDiff line numberDiff line change@@ -139,7 +139,9 @@ PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)

139139return_PyInterpreterFrame_LASTI(frame) *sizeof(_Py_CODEUNIT);

140140}

141141142-int

142+// NOTE: We allow racy accesses to the instruction pointer from other threads

143+// for sys._current_frames() and similar APIs.

144+int_Py_NO_SANITIZE_THREAD

143145PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame*frame)

144146{

145147intaddr=_PyInterpreterFrame_LASTI(frame) *sizeof(_Py_CODEUNIT);