aboutsummaryrefslogtreecommitdiff
path: root/libunwind
diff options
context:
space:
mode:
authorLouis Dionne <ldionne.2@gmail.com>2024-01-09 10:39:14 -0500
committerGitHub <noreply@github.com>2024-01-09 10:39:14 -0500
commitca06c330fd07f05e65a638892c32ca1474d47b5e (patch)
tree7bec5b463890ce5ecc06654a7484fe7f97ed9745 /libunwind
parent07c9189fcc063bdf6219d2733843c89cde3991e1 (diff)
downloadllvm-ca06c330fd07f05e65a638892c32ca1474d47b5e.zip
llvm-ca06c330fd07f05e65a638892c32ca1474d47b5e.tar.gz
llvm-ca06c330fd07f05e65a638892c32ca1474d47b5e.tar.bz2
[libc++] Allow running the test suite with optimizations (#68753)
This patch adds a configuration of the libc++ test suite that enables optimizations when building the tests. It also adds a new CI configuration to exercise this on a regular basis. This is added in the context of [1], which requires building with optimizations in order to hit the bug. [1]: https://github.com/llvm/llvm-project/issues/68552
Diffstat (limited to 'libunwind')
-rw-r--r--libunwind/test/libunwind_02.pass.cpp28
-rw-r--r--libunwind/test/unw_resume.pass.cpp2
-rw-r--r--libunwind/test/unwind_leaffunction.pass.cpp20
3 files changed, 36 insertions, 14 deletions
diff --git a/libunwind/test/libunwind_02.pass.cpp b/libunwind/test/libunwind_02.pass.cpp
index ea34cd5..9fd8e5d 100644
--- a/libunwind/test/libunwind_02.pass.cpp
+++ b/libunwind/test/libunwind_02.pass.cpp
@@ -21,7 +21,8 @@
#define EXPECTED_NUM_FRAMES 50
#define NUM_FRAMES_UPPER_BOUND 100
-_Unwind_Reason_Code callback(_Unwind_Context *context, void *cnt) {
+__attribute__((noinline)) _Unwind_Reason_Code callback(_Unwind_Context *context,
+ void *cnt) {
(void)context;
int *i = (int *)cnt;
++*i;
@@ -31,7 +32,7 @@ _Unwind_Reason_Code callback(_Unwind_Context *context, void *cnt) {
return _URC_NO_REASON;
}
-void test_backtrace() {
+__attribute__((noinline)) void test_backtrace() {
int n = 0;
_Unwind_Backtrace(&callback, &n);
if (n < EXPECTED_NUM_FRAMES) {
@@ -39,17 +40,34 @@ void test_backtrace() {
}
}
-int test(int i) {
+// These functions are effectively the same, but we have to be careful to avoid
+// unwanted optimizations that would mess with the number of frames we expect.
+// Surprisingly, slapping `noinline` is not sufficient -- we also have to avoid
+// writing the function in a way that the compiler can easily spot tail
+// recursion.
+__attribute__((noinline)) int test1(int i);
+__attribute__((noinline)) int test2(int i);
+
+__attribute__((noinline)) int test1(int i) {
+ if (i == 0) {
+ test_backtrace();
+ return 0;
+ } else {
+ return i + test2(i - 1);
+ }
+}
+
+__attribute__((noinline)) int test2(int i) {
if (i == 0) {
test_backtrace();
return 0;
} else {
- return i + test(i - 1);
+ return i + test1(i - 1);
}
}
int main(int, char**) {
- int total = test(50);
+ int total = test1(50);
assert(total == 1275);
return 0;
}
diff --git a/libunwind/test/unw_resume.pass.cpp b/libunwind/test/unw_resume.pass.cpp
index 08e8d4e..2b7470b 100644
--- a/libunwind/test/unw_resume.pass.cpp
+++ b/libunwind/test/unw_resume.pass.cpp
@@ -15,7 +15,7 @@
#include <libunwind.h>
-void test_unw_resume() {
+__attribute__((noinline)) void test_unw_resume() {
unw_context_t context;
unw_cursor_t cursor;
diff --git a/libunwind/test/unwind_leaffunction.pass.cpp b/libunwind/test/unwind_leaffunction.pass.cpp
index 8c9912e..112a596 100644
--- a/libunwind/test/unwind_leaffunction.pass.cpp
+++ b/libunwind/test/unwind_leaffunction.pass.cpp
@@ -28,7 +28,7 @@ _Unwind_Reason_Code frame_handler(struct _Unwind_Context* ctx, void* arg) {
(void)arg;
Dl_info info = { 0, 0, 0, 0 };
- // Unwind until the main is reached, above frames deeped on the platform and
+ // Unwind until the main is reached, above frames depend on the platform and
// architecture.
if (dladdr(reinterpret_cast<void *>(_Unwind_GetIP(ctx)), &info) &&
info.dli_sname && !strcmp("main", info.dli_sname)) {
@@ -43,18 +43,22 @@ void signal_handler(int signum) {
_Exit(-1);
}
-__attribute__((noinline)) void crashing_leaf_func(void) {
+__attribute__((noinline)) void crashing_leaf_func(int do_trap) {
// libunwind searches for the address before the return address which points
- // to the trap instruction. NOP guarantees the trap instruction is not the
- // first instruction of the function.
- // We should keep this here for other unwinders that also decrement pc.
- __asm__ __volatile__("nop");
- __builtin_trap();
+ // to the trap instruction. We make the trap conditional and prevent inlining
+ // of the function to ensure that the compiler doesn't remove the `ret`
+ // instruction altogether.
+ //
+ // It's also important that the trap instruction isn't the first instruction
+ // in the function (which it isn't because of the branch) for other unwinders
+ // that also decrement pc.
+ if (do_trap)
+ __builtin_trap();
}
int main(int, char**) {
signal(SIGTRAP, signal_handler);
signal(SIGILL, signal_handler);
- crashing_leaf_func();
+ crashing_leaf_func(1);
return -2;
}