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

Reply via email to