tsan: check that signal handlers do not spoil errno.


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@159264 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index 41a1e80..aa7f9ab 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -66,6 +66,8 @@
 
 typedef void (*sighandler_t)(int sig);
 
+#define errno (*__errno_location())
+
 union pthread_attr_t {
   char size[kPthreadAttrSize];
   void *align;
@@ -450,7 +452,7 @@
   if (*addr) {
     if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) {
       if (flags & MAP_FIXED) {
-        *__errno_location() = EINVAL;
+        errno = EINVAL;
         return false;
       } else {
         *addr = 0;
@@ -1349,10 +1351,25 @@
       signal->armed = false;
       if (sigactions[sig].sa_handler != SIG_DFL
           && sigactions[sig].sa_handler != SIG_IGN) {
+        // Insure that the handler does not spoil errno.
+        const int saved_errno = errno;
+        errno = 0;
         if (signal->sigaction)
           sigactions[sig].sa_sigaction(sig, &signal->siginfo, &uctx);
         else
           sigactions[sig].sa_handler(sig);
+        if (errno != 0) {
+          ScopedInRtl in_rtl;
+          StackTrace stack;
+          uptr pc = signal->sigaction ?
+              (uptr)sigactions[sig].sa_sigaction :
+              (uptr)sigactions[sig].sa_handler;
+          stack.Init(&pc, 1);
+          ScopedReport rep(ReportTypeErrnoInSignal);
+          rep.AddStack(&stack);
+          OutputReport(rep, rep.GetReport()->stacks[0]);
+        }
+        errno = saved_errno;
       }
     }
   }
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index 95ccf91..cc3b5d7 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -40,6 +40,8 @@
     TsanPrintf("destroy of a locked mutex");
   else if (typ == ReportTypeSignalUnsafe)
     TsanPrintf("signal-unsafe call inside of a signal");
+  else if (typ == ReportTypeErrnoInSignal)
+    TsanPrintf("signal handler spoils errno");
 
   TsanPrintf(" (pid=%d)\n", GetPid());
 }
diff --git a/lib/tsan/rtl/tsan_report.h b/lib/tsan/rtl/tsan_report.h
index 8bf863d..d139296 100644
--- a/lib/tsan/rtl/tsan_report.h
+++ b/lib/tsan/rtl/tsan_report.h
@@ -24,6 +24,7 @@
   ReportTypeThreadLeak,
   ReportTypeMutexDestroyLocked,
   ReportTypeSignalUnsafe,
+  ReportTypeErrnoInSignal,
 };
 
 struct ReportStack {