Home | History | Annotate | Download | only in tests
      1 //===-- sanitizer_stacktrace_test.cc --------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "sanitizer_common/sanitizer_common.h"
     15 #include "sanitizer_common/sanitizer_stacktrace.h"
     16 #include "gtest/gtest.h"
     17 
     18 namespace __sanitizer {
     19 
     20 class FastUnwindTest : public ::testing::Test {
     21  protected:
     22   virtual void SetUp();
     23   bool TryFastUnwind(uptr max_depth) {
     24     if (!StackTrace::WillUseFastUnwind(true))
     25       return false;
     26     trace.Unwind(max_depth, start_pc, (uptr)&fake_stack[0], 0, fake_top,
     27                  fake_bottom, true);
     28     return true;
     29   }
     30 
     31   uptr fake_stack[10];
     32   uptr start_pc;
     33   uptr fake_top;
     34   uptr fake_bottom;
     35   StackTrace trace;
     36 };
     37 
     38 static uptr PC(uptr idx) {
     39   return (1<<20) + idx;
     40 }
     41 
     42 void FastUnwindTest::SetUp() {
     43   // Fill an array of pointers with fake fp+retaddr pairs.  Frame pointers have
     44   // even indices.
     45   for (uptr i = 0; i+1 < ARRAY_SIZE(fake_stack); i += 2) {
     46     fake_stack[i] = (uptr)&fake_stack[i+2];  // fp
     47     fake_stack[i+1] = PC(i + 1); // retaddr
     48   }
     49   // Mark the last fp as zero to terminate the stack trace.
     50   fake_stack[RoundDownTo(ARRAY_SIZE(fake_stack) - 1, 2)] = 0;
     51 
     52   // Top is two slots past the end because FastUnwindStack subtracts two.
     53   fake_top = (uptr)&fake_stack[ARRAY_SIZE(fake_stack) + 2];
     54   // Bottom is one slot before the start because FastUnwindStack uses >.
     55   fake_bottom = (uptr)&fake_stack[-1];
     56   start_pc = PC(0);
     57 }
     58 
     59 TEST_F(FastUnwindTest, Basic) {
     60   if (!TryFastUnwind(kStackTraceMax))
     61     return;
     62   // Should get all on-stack retaddrs and start_pc.
     63   EXPECT_EQ(6U, trace.size);
     64   EXPECT_EQ(start_pc, trace.trace[0]);
     65   for (uptr i = 1; i <= 5; i++) {
     66     EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
     67   }
     68 }
     69 
     70 // From: http://code.google.com/p/address-sanitizer/issues/detail?id=162
     71 TEST_F(FastUnwindTest, FramePointerLoop) {
     72   // Make one fp point to itself.
     73   fake_stack[4] = (uptr)&fake_stack[4];
     74   if (!TryFastUnwind(kStackTraceMax))
     75     return;
     76   // Should get all on-stack retaddrs up to the 4th slot and start_pc.
     77   EXPECT_EQ(4U, trace.size);
     78   EXPECT_EQ(start_pc, trace.trace[0]);
     79   for (uptr i = 1; i <= 3; i++) {
     80     EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
     81   }
     82 }
     83 
     84 TEST_F(FastUnwindTest, MisalignedFramePointer) {
     85   // Make one fp misaligned.
     86   fake_stack[4] += 3;
     87   if (!TryFastUnwind(kStackTraceMax))
     88     return;
     89   // Should get all on-stack retaddrs up to the 4th slot and start_pc.
     90   EXPECT_EQ(4U, trace.size);
     91   EXPECT_EQ(start_pc, trace.trace[0]);
     92   for (uptr i = 1; i < 4U; i++) {
     93     EXPECT_EQ(PC(i*2 - 1), trace.trace[i]);
     94   }
     95 }
     96 
     97 TEST_F(FastUnwindTest, OneFrameStackTrace) {
     98   if (!TryFastUnwind(1))
     99     return;
    100   EXPECT_EQ(1U, trace.size);
    101   EXPECT_EQ(start_pc, trace.trace[0]);
    102   EXPECT_EQ((uptr)&fake_stack[0], trace.top_frame_bp);
    103 }
    104 
    105 TEST_F(FastUnwindTest, ZeroFramesStackTrace) {
    106   if (!TryFastUnwind(0))
    107     return;
    108   EXPECT_EQ(0U, trace.size);
    109   EXPECT_EQ(0U, trace.top_frame_bp);
    110 }
    111 
    112 TEST(SlowUnwindTest, ShortStackTrace) {
    113   if (StackTrace::WillUseFastUnwind(false))
    114     return;
    115   StackTrace stack;
    116   uptr pc = StackTrace::GetCurrentPc();
    117   uptr bp = GET_CURRENT_FRAME();
    118   stack.Unwind(0, pc, bp, 0, 0, 0, false);
    119   EXPECT_EQ(0U, stack.size);
    120   EXPECT_EQ(0U, stack.top_frame_bp);
    121   stack.Unwind(1, pc, bp, 0, 0, 0, false);
    122   EXPECT_EQ(1U, stack.size);
    123   EXPECT_EQ(pc, stack.trace[0]);
    124   EXPECT_EQ(bp, stack.top_frame_bp);
    125 }
    126 
    127 }  // namespace __sanitizer
    128