Issue |
134358
|
Summary |
[TSAN] Handling of nested pending signals by TSan results in blocked signals in user code.
|
Labels |
new issue
|
Assignees |
|
Reporter |
Michael387168
|
I have a multithreaded Linux application that heavily relies on signals. Unfortunately, ThreadSanitizer doesn't seem to support nested signals, which causes my application to hang.
I am using TSan provided with gcc and I built gcc (commit 3e0768d2ffde3f20c5baa92d33869f0c196245c4) myself in order to debug ThreadSanitizer. Unfortunately, I don't know where to find the TSan version used by gcc with this commit. This was the first time I built gcc, so I hope it's reasonably okay.
gcc -v
```
Using built-in specs.
COLLECT_GCC=./gcc
COLLECT_LTO_WRAPPER=/usr/local/gcc/libexec/gcc/x86_64-pc-linux-gnu/15.0.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../configure --prefix=/usr/local/gcc --enable-languages=c,c++ --disable-bootstrap --with-dwarf2 --enable-checking=no CFLAGS='-g -O0' CXXFLAGS='-g -O0'
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 15.0.1 20250327 (experimental) (GCC)
```
Here's what happens:
1. A thread receives a signal.
2. TSan catches the signal with its `sighandler()` and increments `TheadState::pending_signals`.
3. TSan intercepts a call made by the thread and handles the pending signal in `ProcessPendingSignalsImpl()`.
4. `ProcessPendingSignalsImpl()` decrements `TheadState::pending_signals`, stores the old signal mask/set in `ThreadSignalContext::oldset` of the thread and executes the application's signal handler for the pending signal.
5. The application's signal calls `sigsuspend()`, a signal-safe function, to block the thread until it receives another signal.
6. When the other signal `sigsuspend()` is waiting for was caught, TSan's `sighandler()` is executed again incrementing `TheadState::pending_signals`.
7. Before leaving the `sigsuspend()` call made by the application's signal handler, TSan calls `ProcessPendingSignalsImpl()` to process the new pending signal.
8. `ProcessPendingSignalsImpl()` decrements `TheadState::pending_signals` and stores again the old signal mask/set in `ThreadSignalContext::oldset` of the thread. Unfortunately, this overwrites the previous stored old set. The previous old set, which had most signals unblocked, is now overwritten with a set that is used by the first call to `ProcessPendingSignalsImpl()`. Now, when TSan returns from the nested call to `ProcessPendingSignalsImpl()`, it restores the old set with all signals blocked and when TSan returns from the first `ProcessPendingSignalsImpl()`, it again restores the same old set with all signals blocked.
9. My application continues execution with all signals blocked, although they should be unblocked, resulting in the application hanging.
Is there a workaround for this issue or is this something that needs to be fixed in TSan in order to work?
Or am I doing something wrong?
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs