[compiler-rt] r190603 - [asan] add a test for use-after-return and exceptions and fix it. Not 100% sure this is a complete fix, will keep looking for harder cases.

Kostya Serebryany kcc at google.com
Thu Sep 12 06:25:29 PDT 2013


Author: kcc
Date: Thu Sep 12 08:25:29 2013
New Revision: 190603

URL: http://llvm.org/viewvc/llvm-project?rev=190603&view=rev
Log:
[asan] add a test for use-after-return and exceptions and fix it. Not 100% sure this is a complete fix, will keep looking for harder cases.

Added:
    compiler-rt/trunk/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_fake_stack.cc
    compiler-rt/trunk/lib/asan/asan_fake_stack.h
    compiler-rt/trunk/lib/asan/asan_rtl.cc

Modified: compiler-rt/trunk/lib/asan/asan_fake_stack.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_fake_stack.cc?rev=190603&r1=190602&r2=190603&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_fake_stack.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_fake_stack.cc Thu Sep 12 08:25:29 2013
@@ -25,6 +25,8 @@ void FakeStack::PoisonAll(u8 magic) {
 FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
                                uptr real_stack) {
   CHECK_LT(class_id, kNumberOfSizeClasses);
+  if (needs_gc_)
+    GC(real_stack);
   uptr &hint_position = hint_position_[class_id];
   const int num_iter = NumberOfFrames(stack_size_log, class_id);
   u8 *flags = GetFlags(stack_size_log, class_id);
@@ -38,6 +40,7 @@ FakeFrame *FakeStack::Allocate(uptr stac
           GetFrame(stack_size_log, class_id, pos));
       res->real_stack = real_stack;
       res->class_id = class_id;
+      allocated_from_size_class_mask_ |= 1UL << class_id;
       return res;
     }
   }
@@ -70,6 +73,35 @@ uptr FakeStack::AddrIsInFakeStack(uptr p
   return base + pos * BytesInSizeClass(class_id);
 }
 
+void FakeStack::HandleNoReturn() {
+  needs_gc_ = true;
+}
+
+// When throw, longjmp or some such happens we don't call OnFree() and
+// as the result may leak one or more fake frames, but the good news is that
+// we are notified about all such events by HandleNoReturn().
+// If we recently had such no-return event we need to collect garbage frames.
+// We do it based on their 'real_stack' values -- everything that is lower
+// than the current real_stack is garbage.
+NOINLINE void FakeStack::GC(uptr real_stack) {
+  uptr collected = 0;
+  for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
+    if (!(allocated_from_size_class_mask_ & (1UL << class_id))) continue;
+    u8 *flags = GetFlags(stack_size_log(), class_id);
+    for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
+         i++) {
+      if (flags[i] == 0) continue;  // not allocated.
+      FakeFrame *ff = reinterpret_cast<FakeFrame *>(
+          GetFrame(stack_size_log(), class_id, i));
+      if (ff->real_stack < real_stack) {
+        flags[i] = 0;
+        collected++;
+      }
+    }
+  }
+  needs_gc_ = false;
+}
+
 ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size, uptr real_stack) {
   AsanThread *t = GetCurrentThread();
   if (!t) return real_stack;

Modified: compiler-rt/trunk/lib/asan/asan_fake_stack.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_fake_stack.h?rev=190603&r1=190602&r2=190603&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_fake_stack.h (original)
+++ compiler-rt/trunk/lib/asan/asan_fake_stack.h Thu Sep 12 08:25:29 2013
@@ -153,15 +153,21 @@ class FakeStack {
 
   uptr stack_size_log() const { return stack_size_log_; }
 
+  void HandleNoReturn();
+  void GC(uptr real_stack);
+
  private:
   FakeStack() { }
-  static const uptr kFlagsOffset = 4096;  // There is were flags begin.
+  static const uptr kFlagsOffset = 4096;  // This is were the flags begin.
   // Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID
   COMPILER_CHECK(kNumberOfSizeClasses == 11);
   static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
 
   uptr hint_position_[kNumberOfSizeClasses];
   uptr stack_size_log_;
+  // a bit is set if something was allocated from the corresponding size class.
+  uptr allocated_from_size_class_mask_;
+  bool needs_gc_;
 };
 
 }  // namespace __asan

Modified: compiler-rt/trunk/lib/asan/asan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_rtl.cc?rev=190603&r1=190602&r2=190603&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_rtl.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_rtl.cc Thu Sep 12 08:25:29 2013
@@ -427,6 +427,8 @@ void NOINLINE __asan_handle_no_return()
     return;
   }
   PoisonShadow(bottom, top - bottom, 0);
+  if (curr_thread->has_fake_stack())
+    curr_thread->fake_stack()->HandleNoReturn();
 }
 
 void NOINLINE __asan_set_death_callback(void (*callback)(void)) {

Added: compiler-rt/trunk/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc?rev=190603&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc (added)
+++ compiler-rt/trunk/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc Thu Sep 12 08:25:29 2013
@@ -0,0 +1,27 @@
+// Test that use-after-return works with exceptions.
+// RUN: %clangxx_asan -fsanitize=use-after-return -O0 %s -o %t && %t
+
+#include <stdio.h>
+
+volatile char *g;
+
+void Func(int depth) {
+  char frame[100];
+  g = &frame[0];
+  if (depth)
+    Func(depth - 1);
+  else
+    throw 1;
+}
+
+int main(int argc, char **argv) {
+  for (int i = 0; i < 4000; i++) {
+    try {
+      Func(argc * 100);
+    } catch(...) {
+    }
+    if ((i % 1000) == 0)
+      fprintf(stderr, "done [%d]\n", i);
+  }
+  return 0;
+}





More information about the llvm-commits mailing list