1 //===-- sanitizer_stacktrace_test.cpp -------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_stacktrace.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include "sanitizer_common/sanitizer_common.h"
23 #include "sanitizer_internal_defs.h"
25 using testing::ContainsRegex
;
26 using testing::MatchesRegex
;
28 namespace __sanitizer
{
30 class FastUnwindTest
: public ::testing::Test
{
33 virtual void TearDown();
39 const uptr fake_stack_size
= 10;
45 BufferedStackTrace trace
;
47 #if defined(__loongarch__) || defined(__riscv)
48 const uptr kFpOffset
= 4;
49 const uptr kBpOffset
= 2;
51 const uptr kFpOffset
= 2;
52 const uptr kBpOffset
= 0;
56 CommonFlags tmp_flags_
;
59 static uptr
PC(uptr idx
) {
63 void FastUnwindTest::SetUp() {
64 size_t ps
= GetPageSize();
65 mapping
= MmapOrDie(2 * ps
, "FastUnwindTest");
66 MprotectNoAccess((uptr
)mapping
, ps
);
68 // Unwinder may peek 1 word down from the starting FP.
69 fake_stack
= (uhwptr
*)((uptr
)mapping
+ ps
+ sizeof(uhwptr
));
71 // Fill an array of pointers with fake fp+retaddr pairs. Frame pointers have
73 for (uptr i
= 0; i
+ 1 < fake_stack_size
; i
+= 2) {
74 fake_stack
[i
] = (uptr
)&fake_stack
[i
+ kFpOffset
]; // fp
75 fake_stack
[i
+1] = PC(i
+ 1); // retaddr
77 // Mark the last fp point back up to terminate the stack trace.
78 fake_stack
[RoundDownTo(fake_stack_size
- 1, 2)] = (uhwptr
)&fake_stack
[0];
80 // Top is two slots past the end because UnwindFast subtracts two.
81 fake_top
= (uhwptr
)&fake_stack
[fake_stack_size
+ kFpOffset
];
82 // Bottom is one slot before the start because UnwindFast uses >.
83 fake_bottom
= (uhwptr
)mapping
;
84 fake_bp
= (uptr
)&fake_stack
[kBpOffset
];
87 tmp_flags_
.CopyFrom(*common_flags());
90 void FastUnwindTest::TearDown() {
91 size_t ps
= GetPageSize();
92 UnmapOrDie(mapping
, 2 * ps
);
94 // Restore default flags.
95 OverrideCommonFlags(tmp_flags_
);
98 #if SANITIZER_CAN_FAST_UNWIND
101 // Fake stacks don't meet SPARC UnwindFast requirements.
102 #define SKIP_ON_SPARC(x) DISABLED_##x
104 #define SKIP_ON_SPARC(x) x
107 void FastUnwindTest::UnwindFast() {
108 trace
.UnwindFast(start_pc
, fake_bp
, fake_top
, fake_bottom
, kStackTraceMax
);
111 TEST_F(FastUnwindTest
, SKIP_ON_SPARC(Basic
)) {
113 // Should get all on-stack retaddrs and start_pc.
114 EXPECT_EQ(6U, trace
.size
);
115 EXPECT_EQ(start_pc
, trace
.trace
[0]);
116 for (uptr i
= 1; i
<= 5; i
++) {
117 EXPECT_EQ(PC(i
*2 - 1), trace
.trace
[i
]);
121 // From: https://github.com/google/sanitizers/issues/162
122 TEST_F(FastUnwindTest
, SKIP_ON_SPARC(FramePointerLoop
)) {
123 // Make one fp point to itself.
124 fake_stack
[4] = (uhwptr
)&fake_stack
[4];
126 // Should get all on-stack retaddrs up to the 4th slot and start_pc.
127 EXPECT_EQ(4U, trace
.size
);
128 EXPECT_EQ(start_pc
, trace
.trace
[0]);
129 for (uptr i
= 1; i
<= 3; i
++) {
130 EXPECT_EQ(PC(i
*2 - 1), trace
.trace
[i
]);
134 TEST_F(FastUnwindTest
, SKIP_ON_SPARC(MisalignedFramePointer
)) {
135 // Make one fp misaligned.
138 // Should get all on-stack retaddrs up to the 4th slot and start_pc.
139 EXPECT_EQ(4U, trace
.size
);
140 EXPECT_EQ(start_pc
, trace
.trace
[0]);
141 for (uptr i
= 1; i
< 4U; i
++) {
142 EXPECT_EQ(PC(i
*2 - 1), trace
.trace
[i
]);
146 TEST_F(FastUnwindTest
, OneFrameStackTrace
) {
147 trace
.Unwind(start_pc
, fake_bp
, nullptr, true, 1);
148 EXPECT_EQ(1U, trace
.size
);
149 EXPECT_EQ(start_pc
, trace
.trace
[0]);
150 EXPECT_EQ((uhwptr
)&fake_stack
[kBpOffset
], trace
.top_frame_bp
);
153 TEST_F(FastUnwindTest
, ZeroFramesStackTrace
) {
154 trace
.Unwind(start_pc
, fake_bp
, nullptr, true, 0);
155 EXPECT_EQ(0U, trace
.size
);
156 EXPECT_EQ(0U, trace
.top_frame_bp
);
159 TEST_F(FastUnwindTest
, SKIP_ON_SPARC(FPBelowPrevFP
)) {
160 // The next FP points to unreadable memory inside the stack limits, but below
162 fake_stack
[0] = (uhwptr
)&fake_stack
[-50];
163 fake_stack
[1] = PC(1);
165 EXPECT_EQ(2U, trace
.size
);
166 EXPECT_EQ(PC(0), trace
.trace
[0]);
167 EXPECT_EQ(PC(1), trace
.trace
[1]);
170 TEST_F(FastUnwindTest
, SKIP_ON_SPARC(CloseToZeroFrame
)) {
171 // Make one pc a NULL pointer.
174 // The stack should be truncated at the NULL pointer (and not include it).
175 EXPECT_EQ(3U, trace
.size
);
176 EXPECT_EQ(start_pc
, trace
.trace
[0]);
177 for (uptr i
= 1; i
< 3U; i
++) {
178 EXPECT_EQ(PC(i
*2 - 1), trace
.trace
[i
]);
182 using StackPrintTest
= FastUnwindTest
;
184 TEST_F(StackPrintTest
, SKIP_ON_SPARC(ContainsFullTrace
)) {
185 // Override stack trace format to make testing code independent of default
188 flags
.CopyFrom(*common_flags());
189 flags
.stack_trace_format
= "#%n %p";
190 OverrideCommonFlags(flags
);
195 trace
.PrintTo(buf
, sizeof(buf
));
196 EXPECT_THAT(std::string(buf
),
197 MatchesRegex("(#[0-9]+ 0x[0-9a-f]+\n){" +
198 std::to_string(trace
.size
) + "}\n"));
201 TEST_F(StackPrintTest
, SKIP_ON_SPARC(TruncatesContents
)) {
205 uptr actual_len
= trace
.PrintTo(buf
, sizeof(buf
));
206 ASSERT_LT(actual_len
, sizeof(buf
));
209 trace
.PrintTo(tinybuf
, sizeof(tinybuf
));
211 // This the truncation case.
212 ASSERT_GT(actual_len
, sizeof(tinybuf
));
214 // The truncated contents should be a prefix of the full contents.
215 size_t lastpos
= sizeof(tinybuf
) - 1;
216 EXPECT_EQ(strncmp(buf
, tinybuf
, lastpos
), 0);
217 EXPECT_EQ(tinybuf
[lastpos
], '\0');
219 // Full bufffer has more contents...
220 EXPECT_NE(buf
[lastpos
], '\0');
223 TEST_F(StackPrintTest
, SKIP_ON_SPARC(WorksWithEmptyStack
)) {
225 trace
.PrintTo(buf
, sizeof(buf
));
226 EXPECT_NE(strstr(buf
, "<empty stack>"), nullptr);
229 TEST_F(StackPrintTest
, SKIP_ON_SPARC(ReturnsCorrectLength
)) {
233 uptr len
= trace
.PrintTo(buf
, sizeof(buf
));
234 size_t actual_len
= strlen(buf
);
235 ASSERT_LT(len
, sizeof(buf
));
236 EXPECT_EQ(len
, actual_len
);
239 len
= trace
.PrintTo(tinybuf
, sizeof(tinybuf
));
240 size_t truncated_len
= strlen(tinybuf
);
241 ASSERT_GE(len
, sizeof(tinybuf
));
242 EXPECT_EQ(len
, actual_len
);
243 EXPECT_EQ(truncated_len
, sizeof(tinybuf
) - 1);
246 TEST_F(StackPrintTest
, SKIP_ON_SPARC(AcceptsZeroSize
)) {
249 EXPECT_GT(trace
.PrintTo(buf
, 0), 0u);
252 using StackPrintDeathTest
= StackPrintTest
;
254 TEST_F(StackPrintDeathTest
, SKIP_ON_SPARC(RequiresNonNullBuffer
)) {
256 EXPECT_DEATH(trace
.PrintTo(NULL
, 100), "");
259 #endif // SANITIZER_CAN_FAST_UNWIND
261 TEST(SlowUnwindTest
, ShortStackTrace
) {
262 BufferedStackTrace stack
;
263 uptr pc
= StackTrace::GetCurrentPc();
264 uptr bp
= GET_CURRENT_FRAME();
265 stack
.Unwind(pc
, bp
, nullptr, false, /*max_depth=*/0);
266 EXPECT_EQ(0U, stack
.size
);
267 EXPECT_EQ(0U, stack
.top_frame_bp
);
268 stack
.Unwind(pc
, bp
, nullptr, false, /*max_depth=*/1);
269 EXPECT_EQ(1U, stack
.size
);
270 EXPECT_EQ(pc
, stack
.trace
[0]);
271 EXPECT_EQ(bp
, stack
.top_frame_bp
);
274 TEST(GetCurrentPc
, Basic
) {
275 // Test that PCs obtained via GET_CURRENT_PC()
276 // and StackTrace::GetCurrentPc() are all different
277 // and are close to the function start.
279 static NOINLINE
void Test() {
283 StackTrace::GetCurrentPc(),
284 StackTrace::GetCurrentPc(),
286 for (uptr i
= 0; i
< ARRAY_SIZE(pcs
); i
++)
287 Printf("pc%zu: 0x%zx\n", i
, pcs
[i
]);
288 for (uptr i
= 1; i
< ARRAY_SIZE(pcs
); i
++) {
289 EXPECT_GT(pcs
[i
], pcs
[0]);
290 EXPECT_LT(pcs
[i
], pcs
[0] + 1000);
291 for (uptr j
= 0; j
< i
; j
++) EXPECT_NE(pcs
[i
], pcs
[j
]);
298 // Dummy implementation. This should never be called, but is required to link
299 // non-optimized builds of this test.
300 void BufferedStackTrace::UnwindImpl(uptr pc
, uptr bp
, void *context
,
301 bool request_fast
, u32 max_depth
) {
305 } // namespace __sanitizer