stacktrace_test.cc (5331B)
1 // Copyright 2023 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "absl/debugging/stacktrace.h" 16 17 #include <stddef.h> 18 #include <stdint.h> 19 20 #include <algorithm> 21 22 #include "gmock/gmock.h" 23 #include "gtest/gtest.h" 24 #include "absl/base/attributes.h" 25 #include "absl/base/config.h" 26 #include "absl/base/optimization.h" 27 #include "absl/types/span.h" 28 29 namespace { 30 31 using ::testing::Contains; 32 33 struct StackTrace { 34 static constexpr int kStackCount = 64; 35 int depth; 36 void* result[kStackCount]; 37 uintptr_t frames[kStackCount]; 38 int sizes[kStackCount]; 39 }; 40 41 // This test is currently only known to pass on Linux x86_64/aarch64. 42 #if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__)) 43 ABSL_ATTRIBUTE_NOINLINE void Unwind(void* p) { 44 ABSL_ATTRIBUTE_UNUSED static void* volatile sink = p; 45 constexpr int kSize = 16; 46 void* stack[kSize]; 47 int frames[kSize]; 48 absl::GetStackTrace(stack, kSize, 0); 49 absl::GetStackFrames(stack, frames, kSize, 0); 50 } 51 52 ABSL_ATTRIBUTE_NOINLINE void HugeFrame() { 53 char buffer[1 << 20]; 54 Unwind(buffer); 55 ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); 56 } 57 58 TEST(StackTrace, HugeFrame) { 59 // Ensure that the unwinder is not confused by very large stack frames. 60 HugeFrame(); 61 ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); 62 } 63 #endif 64 65 #if ABSL_HAVE_BUILTIN(__builtin_frame_address) 66 struct FrameInfo { 67 const void* return_address; 68 uintptr_t frame_address; 69 }; 70 71 // Returns the canonical frame address and return address for the current stack 72 // frame, while capturing the stack trace at the same time. 73 // This performs any platform-specific adjustments necessary to convert from the 74 // compiler built-ins to the expected API outputs. 75 ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. 76 ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. 77 ABSL_ATTRIBUTE_NOINLINE static FrameInfo 78 CaptureBacktraceNoInline(StackTrace& backtrace) { 79 FrameInfo result; 80 result.return_address = __builtin_return_address(0); 81 // Large enough to cover all realistic slots the return address could be in 82 const int kMaxReturnAddressIndex = 5; 83 void* const* bfa = static_cast<void* const*>(__builtin_frame_address(0)); 84 backtrace.depth = absl::internal_stacktrace::GetStackFramesWithContext( 85 backtrace.result, backtrace.frames, backtrace.sizes, 86 StackTrace::kStackCount, /*skip_count=*/0, 87 /*uc=*/nullptr, /*min_dropped_frames=*/nullptr); 88 // Make sure the return address is at a reasonable location in the frame 89 ptrdiff_t i; 90 for (i = 0; i < kMaxReturnAddressIndex; ++i) { 91 // Avoid std::find() here, since it lacks no-sanitize attributes. 92 if (bfa[i] == result.return_address) { 93 break; 94 } 95 } 96 result.frame_address = 97 i < kMaxReturnAddressIndex 98 ? reinterpret_cast<uintptr_t>( 99 bfa + i + 1 /* get the Canonical Frame Address (CFA) */) 100 : 0; 101 return result; 102 } 103 104 TEST(StackTrace, CanonicalFrameAddresses) { 105 // Now capture a stack trace and verify that the return addresses and frame 106 // addresses line up for one frame. 107 StackTrace backtrace; 108 const auto [return_address, frame_address] = 109 CaptureBacktraceNoInline(backtrace); 110 auto return_addresses = absl::MakeSpan(backtrace.result) 111 .subspan(0, static_cast<size_t>(backtrace.depth)); 112 auto frame_addresses = absl::MakeSpan(backtrace.frames) 113 .subspan(0, static_cast<size_t>(backtrace.depth)); 114 115 // Many platforms don't support this by default. 116 bool support_is_expected = false; 117 118 if (support_is_expected) { 119 // If all zeros were returned, that is valid per the function's contract. 120 // It just means we don't support returning frame addresses on this 121 // platform. 122 bool supported = static_cast<size_t>(std::count(frame_addresses.begin(), 123 frame_addresses.end(), 0)) < 124 frame_addresses.size(); 125 EXPECT_TRUE(supported); 126 if (supported) { 127 ASSERT_TRUE(frame_address) 128 << "unable to obtain frame address corresponding to return address"; 129 EXPECT_THAT(return_addresses, Contains(return_address).Times(1)); 130 EXPECT_THAT(frame_addresses, Contains(frame_address).Times(1)); 131 ptrdiff_t ifound = std::find(return_addresses.begin(), 132 return_addresses.end(), return_address) - 133 return_addresses.begin(); 134 // Make sure we found the frame in the first place. 135 ASSERT_LT(ifound, backtrace.depth); 136 // Make sure the frame address actually corresponds to the return 137 // address. 138 EXPECT_EQ(frame_addresses[static_cast<size_t>(ifound)], frame_address); 139 // Make sure the addresses only appear once. 140 } 141 } 142 } 143 #endif 144 145 } // namespace