1 //===-- sanitizer_stacktrace_test.cpp -------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of ThreadSanitizer/AddressSanitizer runtime. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "sanitizer_common/sanitizer_common.h" 14 #include "sanitizer_common/sanitizer_stacktrace.h" 15 #include "gtest/gtest.h" 16 17 namespace __sanitizer { 18 19 class FastUnwindTest : public ::testing::Test { 20 protected: 21 virtual void SetUp(); 22 virtual void TearDown(); 23 24 void UnwindFast(); 25 26 void *mapping; 27 uhwptr *fake_stack; 28 const uptr fake_stack_size = 10; 29 uhwptr start_pc; 30 31 uhwptr fake_bp; 32 uhwptr fake_top; 33 uhwptr fake_bottom; 34 BufferedStackTrace trace; 35 }; 36 37 static uptr PC(uptr idx) { 38 return (1<<20) + idx; 39 } 40 41 void FastUnwindTest::SetUp() { 42 size_t ps = GetPageSize(); 43 mapping = MmapOrDie(2 * ps, "FastUnwindTest"); 44 MprotectNoAccess((uptr)mapping, ps); 45 46 // Unwinder may peek 1 word down from the starting FP. 47 fake_stack = (uhwptr *)((uptr)mapping + ps + sizeof(uhwptr)); 48 49 // Fill an array of pointers with fake fp+retaddr pairs. Frame pointers have 50 // even indices. 51 for (uptr i = 0; i + 1 < fake_stack_size; i += 2) { 52 fake_stack[i] = (uptr)&fake_stack[i+2]; // fp 53 fake_stack[i+1] = PC(i + 1); // retaddr 54 } 55 // Mark the last fp point back up to terminate the stack trace. 56 fake_stack[RoundDownTo(fake_stack_size - 1, 2)] = (uhwptr)&fake_stack[0]; 57 58 // Top is two slots past the end because UnwindFast subtracts two. 59 fake_top = (uhwptr)&fake_stack[fake_stack_size + 2]; 60 // Bottom is one slot before the start because UnwindFast uses >. 61 fake_bottom = (uhwptr)mapping; 62 fake_bp = (uptr)&fake_stack[0]; 63 start_pc = PC(0); 64 } 65 66 void FastUnwindTest::TearDown() { 67 size_t ps = GetPageSize(); 68 UnmapOrDie(mapping, 2 * ps); 69 } 70 71 #if SANITIZER_CAN_FAST_UNWIND 72 73 #ifdef __sparc__ 74 // Fake stacks don't meet SPARC UnwindFast requirements. 75 #define SKIP_ON_SPARC(x) DISABLED_##x 76 #else 77 #define SKIP_ON_SPARC(x) x 78 #endif 79 80 void FastUnwindTest::UnwindFast() { 81 trace.UnwindFast(start_pc, fake_bp, fake_top, fake_bottom, kStackTraceMax); 82 } 83 84 TEST_F(FastUnwindTest, SKIP_ON_SPARC(Basic)) { 85 UnwindFast(); 86 // Should get all on-stack retaddrs and start_pc. 87 EXPECT_EQ(6U, trace.size); 88 EXPECT_EQ(start_pc, trace.trace[0]); 89 for (uptr i = 1; i <= 5; i++) { 90 EXPECT_EQ(PC(i*2 - 1), trace.trace[i]); 91 } 92 } 93 94 // From: https://github.com/google/sanitizers/issues/162 95 TEST_F(FastUnwindTest, SKIP_ON_SPARC(FramePointerLoop)) { 96 // Make one fp point to itself. 97 fake_stack[4] = (uhwptr)&fake_stack[4]; 98 UnwindFast(); 99 // Should get all on-stack retaddrs up to the 4th slot and start_pc. 100 EXPECT_EQ(4U, trace.size); 101 EXPECT_EQ(start_pc, trace.trace[0]); 102 for (uptr i = 1; i <= 3; i++) { 103 EXPECT_EQ(PC(i*2 - 1), trace.trace[i]); 104 } 105 } 106 107 TEST_F(FastUnwindTest, SKIP_ON_SPARC(MisalignedFramePointer)) { 108 // Make one fp misaligned. 109 fake_stack[4] += 3; 110 UnwindFast(); 111 // Should get all on-stack retaddrs up to the 4th slot and start_pc. 112 EXPECT_EQ(4U, trace.size); 113 EXPECT_EQ(start_pc, trace.trace[0]); 114 for (uptr i = 1; i < 4U; i++) { 115 EXPECT_EQ(PC(i*2 - 1), trace.trace[i]); 116 } 117 } 118 119 TEST_F(FastUnwindTest, OneFrameStackTrace) { 120 trace.Unwind(start_pc, fake_bp, nullptr, true, 1); 121 EXPECT_EQ(1U, trace.size); 122 EXPECT_EQ(start_pc, trace.trace[0]); 123 EXPECT_EQ((uhwptr)&fake_stack[0], trace.top_frame_bp); 124 } 125 126 TEST_F(FastUnwindTest, ZeroFramesStackTrace) { 127 trace.Unwind(start_pc, fake_bp, nullptr, true, 0); 128 EXPECT_EQ(0U, trace.size); 129 EXPECT_EQ(0U, trace.top_frame_bp); 130 } 131 132 TEST_F(FastUnwindTest, SKIP_ON_SPARC(FPBelowPrevFP)) { 133 // The next FP points to unreadable memory inside the stack limits, but below 134 // current FP. 135 fake_stack[0] = (uhwptr)&fake_stack[-50]; 136 fake_stack[1] = PC(1); 137 UnwindFast(); 138 EXPECT_EQ(2U, trace.size); 139 EXPECT_EQ(PC(0), trace.trace[0]); 140 EXPECT_EQ(PC(1), trace.trace[1]); 141 } 142 143 TEST_F(FastUnwindTest, SKIP_ON_SPARC(CloseToZeroFrame)) { 144 // Make one pc a NULL pointer. 145 fake_stack[5] = 0x0; 146 UnwindFast(); 147 // The stack should be truncated at the NULL pointer (and not include it). 148 EXPECT_EQ(3U, trace.size); 149 EXPECT_EQ(start_pc, trace.trace[0]); 150 for (uptr i = 1; i < 3U; i++) { 151 EXPECT_EQ(PC(i*2 - 1), trace.trace[i]); 152 } 153 } 154 155 #endif // SANITIZER_CAN_FAST_UNWIND 156 157 TEST(SlowUnwindTest, ShortStackTrace) { 158 BufferedStackTrace stack; 159 uptr pc = StackTrace::GetCurrentPc(); 160 uptr bp = GET_CURRENT_FRAME(); 161 stack.Unwind(pc, bp, nullptr, false, /*max_depth=*/0); 162 EXPECT_EQ(0U, stack.size); 163 EXPECT_EQ(0U, stack.top_frame_bp); 164 stack.Unwind(pc, bp, nullptr, false, /*max_depth=*/1); 165 EXPECT_EQ(1U, stack.size); 166 EXPECT_EQ(pc, stack.trace[0]); 167 EXPECT_EQ(bp, stack.top_frame_bp); 168 } 169 170 } // namespace __sanitizer 171