[libunwind] Ensure test/libunwind_01.pass is not completely inlined
By adding noinline and calling fprintf before returning we ensure that every function will have a distinct call frame and that the return address will always be saved instead of saving the target in main as the result. Before this change all backtraces were always backtrace -> main -> _start, i.e. always exactly three entries. This happenend because all calls were inlined in main() and the test just happenend to pass because there is at least _start before main. I found this while fixing some bugs in libunwind for CHERI and noticed that the test was passing even though the code was completely broken. Obtained from: https://github.com/CTSRD-CHERI/llvm-project Reviewed By: #libunwind, ldionne, MaskRay Differential Revision: https://reviews.llvm.org/D126611
This commit is contained in:
parent
b02d970b43
commit
8df257a6d0
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <libunwind.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void backtrace(int lower_bound) {
|
||||
|
@ -24,9 +25,17 @@ void backtrace(int lower_bound) {
|
|||
unw_cursor_t cursor;
|
||||
unw_init_local(&cursor, &context);
|
||||
|
||||
char buffer[1024];
|
||||
unw_word_t offset = 0;
|
||||
|
||||
int n = 0;
|
||||
do {
|
||||
++n;
|
||||
n++;
|
||||
if (unw_get_proc_name(&cursor, buffer, sizeof(buffer), &offset) == 0) {
|
||||
fprintf(stderr, "Frame %d: %s+%p\n", n, buffer, (void*)offset);
|
||||
} else {
|
||||
fprintf(stderr, "Frame %d: Could not get name for cursor\n", n);
|
||||
}
|
||||
if (n > 100) {
|
||||
abort();
|
||||
}
|
||||
|
@ -37,18 +46,24 @@ void backtrace(int lower_bound) {
|
|||
}
|
||||
}
|
||||
|
||||
void test1(int i) {
|
||||
__attribute__((noinline)) void test1(int i) {
|
||||
fprintf(stderr, "starting %s\n", __func__);
|
||||
backtrace(i);
|
||||
fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved
|
||||
}
|
||||
|
||||
void test2(int i, int j) {
|
||||
__attribute__((noinline)) void test2(int i, int j) {
|
||||
fprintf(stderr, "starting %s\n", __func__);
|
||||
backtrace(i);
|
||||
test1(j);
|
||||
fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved
|
||||
}
|
||||
|
||||
void test3(int i, int j, int k) {
|
||||
__attribute__((noinline)) void test3(int i, int j, int k) {
|
||||
fprintf(stderr, "starting %s\n", __func__);
|
||||
backtrace(i);
|
||||
test2(j, k);
|
||||
fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved
|
||||
}
|
||||
|
||||
void test_no_info() {
|
||||
|
@ -142,9 +157,9 @@ void test_fpreg_get_set() {}
|
|||
#endif
|
||||
|
||||
int main(int, char**) {
|
||||
test1(1);
|
||||
test2(1, 2);
|
||||
test3(1, 2, 3);
|
||||
test1(3);
|
||||
test2(3, 4);
|
||||
test3(3, 4, 5);
|
||||
test_no_info();
|
||||
test_reg_names();
|
||||
test_reg_get_set();
|
||||
|
|
Loading…
Reference in New Issue