[llvm-commits] [compiler-rt] r168508 - in /compiler-rt/trunk/lib/asan: asan_intercepted_functions.h asan_interceptors.cc asan_internal.h asan_posix.cc asan_report.cc asan_win.cc lit_tests/swapcontext_test.cc

Alexey Samsonov samsonov at google.com
Fri Nov 23 01:46:34 PST 2012


Author: samsonov
Date: Fri Nov 23 03:46:34 2012
New Revision: 168508

URL: http://llvm.org/viewvc/llvm-project?rev=168508&view=rev
Log:
[ASan] Add interceptor for swapcontext to fight with false positives in some of its use cases.

Added:
    compiler-rt/trunk/lib/asan/lit_tests/swapcontext_test.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_intercepted_functions.h
    compiler-rt/trunk/lib/asan/asan_interceptors.cc
    compiler-rt/trunk/lib/asan/asan_internal.h
    compiler-rt/trunk/lib/asan/asan_posix.cc
    compiler-rt/trunk/lib/asan/asan_report.cc
    compiler-rt/trunk/lib/asan/asan_win.cc

Modified: compiler-rt/trunk/lib/asan/asan_intercepted_functions.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_intercepted_functions.h?rev=168508&r1=168507&r2=168508&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_intercepted_functions.h (original)
+++ compiler-rt/trunk/lib/asan/asan_intercepted_functions.h Fri Nov 23 03:46:34 2012
@@ -53,8 +53,10 @@
 
 #if !defined(ANDROID) && !defined(_WIN32)
 # define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
+# define ASAN_INTERCEPT_SWAPCONTEXT 1
 #else
 # define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
+# define ASAN_INTERCEPT_SWAPCONTEXT 0
 #endif
 
 // On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it
@@ -88,6 +90,12 @@
 DECLARE_FUNCTION_AND_WRAPPER(void*, signal, int signum, void *handler);
 # endif
 
+// ucontext.h
+# if ASAN_INTERCEPT_SWAPCONTEXT
+DECLARE_FUNCTION_AND_WRAPPER(int, swapcontext, struct ucontext_t *oucp,
+                             struct ucontext_t *ucp);
+# endif
+
 // setjmp.h
 DECLARE_FUNCTION_AND_WRAPPER(void, longjmp, void *env, int value);
 # if ASAN_INTERCEPT__LONGJMP

Modified: compiler-rt/trunk/lib/asan/asan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interceptors.cc?rev=168508&r1=168507&r2=168508&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_interceptors.cc Fri Nov 23 03:46:34 2012
@@ -136,6 +136,28 @@
     struct sigaction *oldact);
 #endif  // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
 
+#if ASAN_INTERCEPT_SWAPCONTEXT
+INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
+            struct ucontext_t *ucp) {
+  static bool reported_warning = false;
+  if (!reported_warning) {
+    Report("WARNING: ASan doesn't fully support makecontext/swapcontext "
+           "functions and may produce false positives in some cases!\n");
+    reported_warning = true;
+  }
+  // Clear shadow memory for new context (it may share stack
+  // with current context).
+  ClearShadowMemoryForContext(ucp);
+  int res = REAL(swapcontext)(oucp, ucp);
+  // swapcontext technically does not return, but program may swap context to
+  // "oucp" later, that would look as if swapcontext() returned 0.
+  // We need to clear shadow for ucp once again, as it may be in arbitrary
+  // state.
+  ClearShadowMemoryForContext(ucp);
+  return res;
+}
+#endif
+
 INTERCEPTOR(void, longjmp, void *env, int val) {
   __asan_handle_no_return();
   REAL(longjmp)(env, val);
@@ -689,6 +711,9 @@
   ASAN_INTERCEPT_FUNC(sigaction);
   ASAN_INTERCEPT_FUNC(signal);
 #endif
+#if ASAN_INTERCEPT_SWAPCONTEXT
+  ASAN_INTERCEPT_FUNC(swapcontext);
+#endif
 #if ASAN_INTERCEPT__LONGJMP
   ASAN_INTERCEPT_FUNC(_longjmp);
 #endif

Modified: compiler-rt/trunk/lib/asan/asan_internal.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_internal.h?rev=168508&r1=168507&r2=168508&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_internal.h (original)
+++ compiler-rt/trunk/lib/asan/asan_internal.h Fri Nov 23 03:46:34 2012
@@ -116,6 +116,7 @@
 void SetAlternateSignalStack();
 void UnsetAlternateSignalStack();
 void InstallSignalHandlers();
+void ClearShadowMemoryForContext(void *context);
 void AsanPlatformThreadInit();
 
 // Wrapper for TLS/TSD.

Modified: compiler-rt/trunk/lib/asan/asan_posix.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_posix.cc?rev=168508&r1=168507&r2=168508&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_posix.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_posix.cc Fri Nov 23 03:46:34 2012
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <ucontext.h>
 #include <unistd.h>
 
 static const uptr kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
@@ -95,6 +96,17 @@
   MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
 }
 
+void ClearShadowMemoryForContext(void *context) {
+  ucontext_t *ucp = (ucontext_t*)context;
+  uptr sp = (uptr)ucp->uc_stack.ss_sp;
+  uptr size = ucp->uc_stack.ss_size;
+  // Align to page size.
+  uptr bottom = sp & ~(kPageSize - 1);
+  size += sp - bottom;
+  size = RoundUpTo(size, kPageSize);
+  PoisonShadow(bottom, size, 0);
+}
+
 // ---------------------- TSD ---------------- {{{1
 
 static pthread_key_t tsd_key;

Modified: compiler-rt/trunk/lib/asan/asan_report.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_report.cc?rev=168508&r1=168507&r2=168508&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_report.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_report.cc Fri Nov 23 03:46:34 2012
@@ -180,7 +180,7 @@
     Printf("    [%zu, %zu) '%s'\n", beg, beg + size, buf);
   }
   Printf("HINT: this may be a false positive if your program uses "
-             "some custom stack unwind mechanism\n"
+             "some custom stack unwind mechanism or swapcontext\n"
              "      (longjmp and C++ exceptions *are* supported)\n");
   DescribeThread(t->summary());
   return true;

Modified: compiler-rt/trunk/lib/asan/asan_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_win.cc?rev=168508&r1=168507&r2=168508&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_win.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_win.cc Fri Nov 23 03:46:34 2012
@@ -139,6 +139,10 @@
   // Nothing here for now.
 }
 
+void ClearShadowMemoryForContext(void *context) {
+  UNIMPLEMENTED();
+}
+
 }  // namespace __asan
 
 // ---------------------- Interface ---------------- {{{1

Added: compiler-rt/trunk/lib/asan/lit_tests/swapcontext_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/lit_tests/swapcontext_test.cc?rev=168508&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/lit_tests/swapcontext_test.cc (added)
+++ compiler-rt/trunk/lib/asan/lit_tests/swapcontext_test.cc Fri Nov 23 03:46:34 2012
@@ -0,0 +1,66 @@
+// Check that ASan plays well with easy cases of makecontext/swapcontext.
+
+// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+ucontext_t orig_context;
+ucontext_t child_context;
+
+void Child(int mode) {
+  char x[32] = {0};  // Stack gets poisoned.
+  printf("Child: %p\n", x);
+  // (a) Do nothing, just return to parent function.
+  // (b) Jump into the original function. Stack remains poisoned unless we do
+  //     something.
+  if (mode == 1) {
+    if (swapcontext(&child_context, &orig_context) < 0) {
+      perror("swapcontext");
+      _exit(0);
+    }
+  }
+}
+
+int Run(int arg, int mode) {
+  const int kStackSize = 1 << 20;
+  char child_stack[kStackSize + 1];
+  printf("Child stack: %p\n", child_stack);
+  // Setup child context.
+  getcontext(&child_context);
+  child_context.uc_stack.ss_sp = child_stack;
+  child_context.uc_stack.ss_size = kStackSize / 2;
+  if (mode == 0) {
+    child_context.uc_link = &orig_context;
+  }
+  makecontext(&child_context, (void (*)())Child, 1, mode);
+  if (swapcontext(&orig_context, &child_context) < 0) {
+    perror("swapcontext");
+    return 0;
+  }
+  // Touch childs's stack to make sure it's unpoisoned.
+  for (int i = 0; i < kStackSize; i++) {
+    child_stack[i] = i;
+  }
+  return child_stack[arg];
+}
+
+int main(int argc, char **argv) {
+  // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext
+  int ret = 0;
+  ret += Run(argc - 1, 0);
+  printf("Test1 passed\n");
+  // CHECK: Test1 passed
+  ret += Run(argc - 1, 1);
+  printf("Test2 passed\n");
+  // CHECK: Test2 passed
+  return ret;
+}





More information about the llvm-commits mailing list