tsan: print signal num in errno spoiling reports

For errno spoiling reports we only print the stack
where the signal handler is invoked. And the top
frame is the signal handler function, which is supposed
to give the info for debugging.
But in same cases the top frame can be some common thunk,
which does not give much info. E.g. for Go/cgo it's always
runtime.cgoSigtramp.

Print the signal number.
This is what we can easily gather and it may give at least
some hints regarding the issue.

Reviewed By: melver, vitalybuka

Differential Revision: https://reviews.llvm.org/D121979
This commit is contained in:
Dmitry Vyukov 2022-03-18 07:24:00 +01:00
parent 00145bcb4c
commit 9e66e5872c
6 changed files with 11 additions and 3 deletions

View file

@ -1964,13 +1964,14 @@ TSAN_INTERCEPTOR(int, pthread_sigmask, int how, const __sanitizer_sigset_t *set,
namespace __tsan {
static void ReportErrnoSpoiling(ThreadState *thr, uptr pc) {
static void ReportErrnoSpoiling(ThreadState *thr, uptr pc, int sig) {
VarSizeStackTrace stack;
// StackTrace::GetNestInstructionPc(pc) is used because return address is
// expected, OutputReport() will undo this.
ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack);
ThreadRegistryLock l(&ctx->thread_registry);
ScopedReport rep(ReportTypeErrnoInSignal);
rep.SetSigNum(sig);
if (!IsFiredSuppression(ctx, ReportTypeErrnoInSignal, stack)) {
rep.AddStack(stack, true);
OutputReport(thr, rep);
@ -2037,7 +2038,7 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
// signal; and it looks too fragile to intercept all ways to reraise a signal.
if (ShouldReport(thr, ReportTypeErrnoInSignal) && !sync && sig != SIGTERM &&
errno != 99)
ReportErrnoSpoiling(thr, pc);
ReportErrnoSpoiling(thr, pc, sig);
errno = saved_errno;
}

View file

@ -306,6 +306,9 @@ void PrintReport(const ReportDesc *rep) {
(int)internal_getpid());
Printf("%s", d.Default());
if (rep->typ == ReportTypeErrnoInSignal)
Printf(" Signal %u handler invoked at:\n", rep->signum);
if (rep->typ == ReportTypeDeadlock) {
char thrbuf[kThreadBufSize];
Printf(" Cycle in lock order graph: ");

View file

@ -108,6 +108,7 @@ class ReportDesc {
Vector<Tid> unique_tids;
ReportStack *sleep;
int count;
int signum = 0;
ReportDesc();
~ReportDesc();

View file

@ -376,6 +376,7 @@ class ScopedReportBase {
void AddLocation(uptr addr, uptr size);
void AddSleep(StackID stack_id);
void SetCount(int count);
void SetSigNum(int sig);
const ReportDesc *GetReport() const;

View file

@ -340,6 +340,8 @@ void ScopedReportBase::AddSleep(StackID stack_id) {
void ScopedReportBase::SetCount(int count) { rep_->count = count; }
void ScopedReportBase::SetSigNum(int sig) { rep_->signum = sig; }
const ReportDesc *ScopedReportBase::GetReport() const { return rep_; }
ScopedReport::ScopedReport(ReportType typ, uptr tag)

View file

@ -46,7 +46,7 @@ int main() {
}
// CHECK: WARNING: ThreadSanitizer: signal handler spoils errno
// CHECK: Signal 27 handler invoked at:
// CHECK: #0 MyHandler(int, {{(__)?}}siginfo{{(_t)?}}*, void*) {{.*}}signal_errno.cpp
// CHECK: main
// CHECK: SUMMARY: ThreadSanitizer: signal handler spoils errno{{.*}}MyHandler