Skip to content

Suppress fence-synchronised dependency reports by default - #4

Merged
nimbrel merged 3 commits into
mainfrom
fix/dependency-suppressions
Sep 27, 2026
Merged

nimbrel merged 3 commits into
mainfrom
fix/dependency-suppressions

Conversation

@nimbrel

@nimbrel nimbrel commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

TSan does not model standalone fences, so reports lying entirely inside some dependencies' synchronisation were filed as "in your extension" and failed runs with no frame of the extension on either access.

Default suppressions now cover:

  • oneshot: the sender's write into the message slot and the drop that frees the channel (the receiver orders them with a relaxed load and fence(Acquire)).
  • crossbeam-epoch 0.9.18 and older: the SealedBag read in pop_if_internal, and freeing a finished thread's Local while try_advance walks the list (0.9.19+ changed these for TSan).
  • glibc thread-local teardown: _dl_deallocate_tls freeing a detached, finished thread's TLS.

Each entry is commented with the reason. Where the top frame is an interceptor (free, memcpy), race_top: cannot target the report, so the entry is a race: naming a function that runs none of the caller's code; a test keeps a reviewed list of those.

  • fixtures/clean/clean-dependency-fences fails in ci and stress without the entries and passes with them.
  • fixtures/racy/race-in-dependency-callbacks still reports races in code those dependencies run for you (a message's Drop, a deferred closure, a thread-local destructor).
  • docs/limitations.md states what the entries cannot see, including that the glibc entry can hide a use-after-free on a finished thread's thread-local reached through an escaped pointer.

clean-dependency-fences exercises oneshot's message handover,
crossbeam-epoch 0.9.18's reclamation and glibc freeing a detached
thread's TLS block from many threads. Every access is ordered, but not
in a way TSan models, so each is reported without suppressions.

race-in-dependency-callbacks races in code those dependencies run on
the extension's behalf: a message's Drop run by oneshot, a closure
deferred to the epoch collector and a thread-local destructor. Those
races must stay reported whatever is suppressed.

Signed-off-by: nimbrel <[email protected]>
…orts

TSan does not model standalone fences and cannot see inside glibc, so
oneshot's handover, crossbeam-epoch's reclamation and a detached
thread's TLS free were filed as races in the extension and failed runs.

Each entry names only the dependency's own function. Where the reported
frame is an interceptor, race_top cannot name it, so a reviewed race:
entry names a function that runs none of the caller's code. The test
checks every entry against synthetic reports: the dependencies' own
reports are hidden, races in callbacks they run are not.

Signed-off-by: nimbrel <[email protected]>
ci.md lists what the defaults cover and how they stay narrow;
limitations.md keeps unknown fence-synchronised dependencies, accesses
of yours ordered only by such a fence, and the use-after-free the glibc
entry could hide.

Signed-off-by: nimbrel <[email protected]>
@nimbrel
nimbrel merged commit a9fa720 into main Sep 27, 2026
6 checks passed
@nimbrel
nimbrel deleted the fix/dependency-suppressions branch September 28, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant