| Issue |
203451
|
| Summary |
[TSan] Missing interceptors for flockfile/ftrylockfile/funlockfile cause false positive data race reports
|
| Labels |
false-positive
|
| Assignees |
|
| Reporter |
lim-james
|
TSan does not intercept `flockfile`, `ftrylockfile`, or `funlockfile`. Observed code that correctly serializes `FILE` access using these POSIX stdio locking primitives is reported as a data race because TSan cannot establish the happens-before relationship through them.
## Reproducible Example
```cpp
#include <cstdio>
#include <thread>
int main() {
int shared_data{} ;
std::jthread a([&]{
flockfile(stdout);
shared_data++; // correctly protected
funlockfile(stdout);
});
std::jthread b([&]{
flockfile(stdout);
shared_data++; // correctly protected
funlockfile(stdout);
});
}
```
Compiler flags
```
-fsanitize=thread
```
[Compiler Explorer example](https://godbolt.org/z/zoM1f7GYz)
## TSan Warning Description
TSan reports a data race on shared data despite both threads holding the file lock when accessing it. The code is accurate, `flockfile` is a POSIX-specified lock per file stream.
## Root Cause
[compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp](https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp) does not contain interceptors for `flockfile`, `ftrylockfile`, or `funlockfile`. TSan therefore sees no synchronization between threads that coordinate through these calls.
## Impact
libstdc++'s `std::print`/`std::println` implementation on Glibc platforms uses `flockfile` for the duration of each print call and is falsely reported as a data race under TSan.
## Suggested fix
Add interceptors analogous to the existing pthread mutex ones:
```cpp
TSAN_INTERCEPTOR(void, flockfile, FILE *file) {
SCOPED_TSAN_INTERCEPTOR(flockfile, file);
REAL(flockfile)(file);
MutexPostLock(thr, pc, (uptr)file,
MutexFlagNotStatic | MutexFlagWriteReentrant);
}
TSAN_INTERCEPTOR(int, ftrylockfile, FILE *file) {
SCOPED_TSAN_INTERCEPTOR(ftrylockfile, file);
int ret = REAL(ftrylockfile)(file);
if (ret == 0)
MutexPostLock(thr, pc, (uptr)file,
MutexFlagNotStatic | MutexFlagWriteReentrant | MutexFlagTryLock);
return ret;
}
TSAN_INTERCEPTOR(void, funlockfile, FILE *file) {
SCOPED_TSAN_INTERCEPTOR(funlockfile, file);
MutexPreUnlock(thr, pc, (uptr)file);
REAL(funlockfile)(file);
}
```
I intend to submit a PR with this fix and a corresponding test.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs