This patch adds synchronization between the creation of the GCD data object and destructor’s execution. It’s far from perfect, because ideally we’d want to synchronize the destruction of the last reference (via dispatch_release) and the destructor’s execution, but intercepting objc_release is problematic.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
It’s far from perfect, because ideally we’d want to synchronize the destruction of the last reference (via dispatch_release) and the destructor’s execution, but intercepting objc_release is problematic.
Why don't we intercept dispatch_release?
lib/tsan/rtl/tsan_libdispatch_mac.cc | ||
---|---|---|
460 ↗ | (On Diff #62736) | Will it work with DISPATCH_DATA_DESTRUCTOR_FREE/DEFAULT? |
- We’d need to intercept both dispatch_release and objc_release, in some cases they can be used interchangeably (toll-free bridging), which means we should add dispatch_retain and objc_retain as well. Theses functions are called *a lot* and I’m worried about performance, but more importantly about all the added synchronization on refcounts, which is going to cause false negatives.
- We cannot tell if the release is going to destroy the object or not. We can’t take a look at the refcount, because that’s an internal implementation detail and it actually changes.
- This will still not cover all the false positives with GCD objects, because there are shortcuts in GCD internals that release/destroy objects without going through dispatch_release.
Still, I’m probably going to try to add those interceptors at some point, but it sounds like quite a non-trivial task to do it right.
Updating the patch to handle DISPATCH_DATA_DESTRUCTOR_FREE and other special values. The original patch actually crashed when these were used (the block that this magic value is pointing to isn’t supposed to be called at all). Thanks!
Also checking when queue is NULL, it seems there is some code that is using it (although the docs isn’t clear what the behavior is then).
lib/tsan/rtl/tsan_libdispatch_mac.cc | ||
---|---|---|
484 ↗ | (On Diff #62867) | Won't this cause false positives? |
lib/tsan/rtl/tsan_libdispatch_mac.cc | ||
---|---|---|
484 ↗ | (On Diff #62867) | I guess you’re right, but we’re currently still using ignore_interceptors_accesses=1 on Darwin to avoid false positives from system libraries, which also suppresses races with free. Anyway, what would be the solution here? Release() on buffer? |
lib/tsan/rtl/tsan_libdispatch_mac.cc | ||
---|---|---|
484 ↗ | (On Diff #62867) |
If destructor == DISPATCH_DATA_DESTRUCTOR_FREE, replace it with a block that calls free? |