@@ -666,6 +666,20 @@ def _tsan_launcher(tmp: Path) -> Path | None:
666666 return launcher if link .returncode == 0 else None
667667
668668
669+ def _access_is_ours (block : str ) -> bool :
670+ """A report counts when one of its two racing accesses was made by the extension itself: the
671+ first stack frame of that access outside the sanitizer runtime is in `ftmod` (generated C or the
672+ header). A race whose accesses are inside libpython (seen on Linux CI: two `PyUnicode_FromString`
673+ memcpys into memory the uninstrumented allocator had handed from one thread to another) is not
674+ about this extension, even when an extension frame calls it further up."""
675+ for part in block .split ("\n \n " )[:2 ]:
676+ frames = [ln for ln in part .splitlines () if ln .strip ().startswith ("#" )]
677+ first = next ((f for f in frames if "libtsan" not in f and "sanitizer_common" not in f ), "" )
678+ if "ftmod" in first :
679+ return True
680+ return False
681+
682+
669683def _tsan_reports (built , tmp : Path , launcher : Path , rt : Path | None ) -> tuple [int , bool ]:
670684 result , path , _ = built
671685 flags = list (cbuild .DEFAULT_FLAGS ) + ["-O1" , "-g" , "-fno-omit-frame-pointer" , "-fsanitize=thread" ]
@@ -682,7 +696,7 @@ def _tsan_reports(built, tmp: Path, launcher: Path, rt: Path | None) -> tuple[in
682696 # CPython itself (seen on Linux CI). Count only reports with a frame of the extension or the
683697 # header: those are the accesses this test is about.
684698 blocks = out .split ("WARNING: ThreadSanitizer" )[1 :]
685- ours = [b for b in blocks if "ftmod" in b or " tp_" in b ]
699+ ours = [b for b in blocks if _access_is_ours ( b ) ]
686700 _tsan_reports .first = ("WARNING: ThreadSanitizer" + ours [0 ])[:4000 ] if ours else ""
687701 return len (ours ), "TSAN-RUN-DONE" in out
688702
0 commit comments