Skip to content

Commit

Permalink
LTO hackery, make unittests pass under LTO, closes #179
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremy-rifkin committed Nov 11, 2024
1 parent 90da056 commit 4cb425f
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 26 deletions.
11 changes: 7 additions & 4 deletions test/unit/from_current.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,24 @@
using namespace std::literals;


// NOTE: returning something and then return stacktrace_from_current_3(line_numbers) * 2; later helps prevent the call from
// being optimized to a jmp
// NOTE: returning something and then return stacktrace_multi_3(line_numbers) * rand(); is done to prevent TCO even
// under LTO https://github.com/jeremy-rifkin/cpptrace/issues/179#issuecomment-2467302052
CPPTRACE_FORCE_NO_INLINE int stacktrace_from_current_3(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
throw std::runtime_error("foobar");
}

CPPTRACE_FORCE_NO_INLINE int stacktrace_from_current_2(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_from_current_3(line_numbers) * 2;
return stacktrace_from_current_3(line_numbers) * rand();
}

CPPTRACE_FORCE_NO_INLINE int stacktrace_from_current_1(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_from_current_2(line_numbers) * 2;
return stacktrace_from_current_2(line_numbers) * rand();
}

TEST(FromCurrent, Basic) {
Expand Down
17 changes: 7 additions & 10 deletions test/unit/from_current_z.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,24 @@
using namespace std::literals;


// NOTE: returning something and then return stacktrace_from_current_3(line_numbers) * 2; later helps prevent the call from
// being optimized to a jmp
// NOTE: returning something and then return stacktrace_multi_3(line_numbers) * rand(); is done to prevent TCO even
// under LTO https://github.com/jeremy-rifkin/cpptrace/issues/179#issuecomment-2467302052
CPPTRACE_FORCE_NO_INLINE int stacktrace_from_current_z_3(std::vector<int>& line_numbers) {
// just here to differentiate from the non-z version to prevent ICF if LTO is being used
[[maybe_unused]] volatile int x = 1;
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
throw std::runtime_error("foobar");
}

CPPTRACE_FORCE_NO_INLINE int stacktrace_from_current_z_2(std::vector<int>& line_numbers) {
// just here to differentiate from the non-z version to prevent ICF if LTO is being used
[[maybe_unused]] volatile int x = 1;
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_from_current_z_3(line_numbers) * 2;
return stacktrace_from_current_z_3(line_numbers) * rand();
}

CPPTRACE_FORCE_NO_INLINE int stacktrace_from_current_z_1(std::vector<int>& line_numbers) {
// just here to differentiate from the non-z version to prevent ICF if LTO is being used
[[maybe_unused]] volatile int x = 1;
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_from_current_z_2(line_numbers) * 2;
return stacktrace_from_current_z_2(line_numbers) * rand();
}

TEST(FromCurrentZ, Basic) {
Expand Down
12 changes: 10 additions & 2 deletions test/unit/object_trace.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <random>
#include <vector>

#include <gtest/gtest.h>
Expand All @@ -19,6 +20,7 @@ TEST(ObjectTrace, Empty) {


CPPTRACE_FORCE_NO_INLINE void object_basic() {
static volatile int lto_guard; lto_guard = lto_guard + 1;
auto trace = cpptrace::generate_object_trace();
EXPECT_FALSE(trace.empty());
EXPECT_NE(trace.frames[0].raw_address, 0);
Expand All @@ -33,6 +35,7 @@ TEST(ObjectTrace, Basic) {


CPPTRACE_FORCE_NO_INLINE void object_basic_resolution() {
static volatile int lto_guard; lto_guard = lto_guard + 1;
auto line = __LINE__ + 1;
auto trace = cpptrace::generate_object_trace().resolve();
ASSERT_GE(trace.frames.size(), 1);
Expand All @@ -49,6 +52,7 @@ TEST(ObjectTrace, BasicResolution) {
// TODO: dbghelp uses raw address, not object
#ifndef _MSC_VER
CPPTRACE_FORCE_NO_INLINE int object_resolve_3(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
auto dummy = cpptrace::generate_trace();
auto dummy_otrace = cpptrace::generate_object_trace();
Expand Down Expand Up @@ -89,14 +93,18 @@ CPPTRACE_FORCE_NO_INLINE int object_resolve_3(std::vector<int>& line_numbers) {
return 2;
}

// NOTE: returning something and then return stacktrace_multi_3(line_numbers) * rand(); is done to prevent TCO even
// under LTO https://github.com/jeremy-rifkin/cpptrace/issues/179#issuecomment-2467302052
CPPTRACE_FORCE_NO_INLINE int object_resolve_2(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return object_resolve_3(line_numbers) * 2;
return object_resolve_3(line_numbers) * rand();
}

CPPTRACE_FORCE_NO_INLINE int object_resolve_1(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return object_resolve_2(line_numbers) * 2;
return object_resolve_2(line_numbers) * rand();
}

TEST(ObjectTrace, Resolution) {
Expand Down
8 changes: 8 additions & 0 deletions test/unit/raw_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ using namespace std::literals;

// NOTE: MSVC likes creating trampoline-like entries for non-static functions
CPPTRACE_FORCE_NO_INLINE static void raw_trace_basic() {
static volatile int lto_guard; lto_guard = lto_guard + 1;
auto raw_trace = cpptrace::generate_raw_trace();
// look for within 90 bytes of the start of the function
ASSERT_GE(raw_trace.frames.size(), 1);
Expand All @@ -27,6 +28,7 @@ CPPTRACE_FORCE_NO_INLINE static void raw_trace_basic() {

#ifndef _MSC_VER
CPPTRACE_FORCE_NO_INLINE void raw_trace_basic_precise() {
static volatile int lto_guard; lto_guard = lto_guard + 1;
a:
auto raw_trace = cpptrace::generate_raw_trace();
b:
Expand Down Expand Up @@ -58,6 +60,7 @@ CPPTRACE_FORCE_NO_INLINE static void raw_trace_multi_2(
cpptrace::frame_ptr parent_low_bound,
cpptrace::frame_ptr parent_high_bound
) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
auto raw_trace = cpptrace::generate_raw_trace();
ASSERT_GE(raw_trace.frames.size(), 2);
EXPECT_GE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(raw_trace_multi_2));
Expand All @@ -67,6 +70,7 @@ CPPTRACE_FORCE_NO_INLINE static void raw_trace_multi_2(
}

CPPTRACE_FORCE_NO_INLINE static void raw_trace_multi_1() {
static volatile int lto_guard; lto_guard = lto_guard + 1;
auto raw_trace = cpptrace::generate_raw_trace();
raw_trace_multi_2(reinterpret_cast<uintptr_t>(raw_trace_multi_1), reinterpret_cast<uintptr_t>(raw_trace_multi_1) + 300);
ASSERT_GE(raw_trace.frames.size(), 1);
Expand All @@ -77,11 +81,13 @@ CPPTRACE_FORCE_NO_INLINE static void raw_trace_multi_1() {
std::vector<std::pair<cpptrace::frame_ptr, cpptrace::frame_ptr>> parents;

CPPTRACE_FORCE_NO_INLINE void record_parent(uintptr_t low_bound, uintptr_t high_bound) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
parents.insert(parents.begin(), {low_bound, high_bound});
}

#ifndef _MSC_VER
CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_3() {
static volatile int lto_guard; lto_guard = lto_guard + 1;
a:
auto raw_trace = cpptrace::generate_raw_trace();
b:
Expand All @@ -102,6 +108,7 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_3() {
}

CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_2() {
static volatile int lto_guard; lto_guard = lto_guard + 1;
a:
auto raw_trace = cpptrace::generate_raw_trace();
b:
Expand Down Expand Up @@ -132,6 +139,7 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_2() {
}

CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_1() {
static volatile int lto_guard; lto_guard = lto_guard + 1;
a:
auto raw_trace = cpptrace::generate_raw_trace();
b:
Expand Down
22 changes: 16 additions & 6 deletions test/unit/stacktrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ TEST(Stacktrace, Empty) {


CPPTRACE_FORCE_NO_INLINE void stacktrace_basic() {
static volatile int lto_guard; lto_guard = lto_guard + 1;
auto line = __LINE__ + 1;
auto trace = cpptrace::generate_trace();
ASSERT_GE(trace.frames.size(), 1);
Expand All @@ -39,9 +40,10 @@ TEST(Stacktrace, Basic) {



// NOTE: returning something and then return stacktrace_multi_3(line_numbers) * 2; later helps prevent the call from
// being optimized to a jmp
// NOTE: returning something and then return stacktrace_multi_3(line_numbers) * rand(); is done to prevent TCO even
// under LTO https://github.com/jeremy-rifkin/cpptrace/issues/179#issuecomment-2467302052
CPPTRACE_FORCE_NO_INLINE int stacktrace_multi_3(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
auto trace = cpptrace::generate_trace();
if(trace.frames.size() < 4) {
Expand All @@ -68,13 +70,15 @@ CPPTRACE_FORCE_NO_INLINE int stacktrace_multi_3(std::vector<int>& line_numbers)
}

CPPTRACE_FORCE_NO_INLINE int stacktrace_multi_2(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_multi_3(line_numbers) * 2;
return stacktrace_multi_3(line_numbers) * rand();
}

CPPTRACE_FORCE_NO_INLINE int stacktrace_multi_1(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_multi_2(line_numbers) * 2;
return stacktrace_multi_2(line_numbers) * rand();
}

TEST(Stacktrace, MultipleFrames) {
Expand All @@ -86,16 +90,19 @@ TEST(Stacktrace, MultipleFrames) {


CPPTRACE_FORCE_NO_INLINE cpptrace::raw_trace stacktrace_raw_resolve_3(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return cpptrace::generate_raw_trace();
}

CPPTRACE_FORCE_NO_INLINE cpptrace::raw_trace stacktrace_raw_resolve_2(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_raw_resolve_3(line_numbers);
}

CPPTRACE_FORCE_NO_INLINE cpptrace::raw_trace stacktrace_raw_resolve_1(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_raw_resolve_2(line_numbers);
}
Expand Down Expand Up @@ -127,6 +134,7 @@ TEST(Stacktrace, RawTraceResolution) {

#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF
CPPTRACE_FORCE_NO_INLINE int stacktrace_inline_resolution_3(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
auto trace = cpptrace::generate_trace();
if(trace.frames.size() < 4) {
Expand Down Expand Up @@ -165,13 +173,15 @@ CPPTRACE_FORCE_NO_INLINE int stacktrace_inline_resolution_3(std::vector<int>& li
}

CPPTRACE_FORCE_INLINE int stacktrace_inline_resolution_2(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_inline_resolution_3(line_numbers) * 2;
return stacktrace_inline_resolution_3(line_numbers) * rand();
}

CPPTRACE_FORCE_NO_INLINE int stacktrace_inline_resolution_1(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_inline_resolution_2(line_numbers) * 2;
return stacktrace_inline_resolution_2(line_numbers) * rand();
}

TEST(Stacktrace, InlineResolution) {
Expand Down
11 changes: 7 additions & 4 deletions test/unit/traced_exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,24 @@
using namespace std::literals;


// NOTE: returning something and then return stacktrace_traced_object_3(line_numbers) * 2; later helps prevent the call from
// being optimized to a jmp
// NOTE: returning something and then return stacktrace_multi_3(line_numbers) * rand(); is done to prevent TCO even
// under LTO https://github.com/jeremy-rifkin/cpptrace/issues/179#issuecomment-2467302052
CPPTRACE_FORCE_NO_INLINE int stacktrace_traced_object_3(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
throw cpptrace::runtime_error("foobar");
}

CPPTRACE_FORCE_NO_INLINE int stacktrace_traced_object_2(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_traced_object_3(line_numbers) * 2;
return stacktrace_traced_object_3(line_numbers) * rand();
}

CPPTRACE_FORCE_NO_INLINE int stacktrace_traced_object_1(std::vector<int>& line_numbers) {
static volatile int lto_guard; lto_guard = lto_guard + 1;
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
return stacktrace_traced_object_2(line_numbers) * 2;
return stacktrace_traced_object_2(line_numbers) * rand();
}

TEST(TracedException, Basic) {
Expand Down

0 comments on commit 4cb425f

Please sign in to comment.