diff --git a/ddprof-lib/src/test/cpp/returnAddressAttribution_ut.cpp b/ddprof-lib/src/test/cpp/returnAddressAttribution_ut.cpp index b7f4e6c0de..564b81faac 100644 --- a/ddprof-lib/src/test/cpp/returnAddressAttribution_ut.cpp +++ b/ddprof-lib/src/test/cpp/returnAddressAttribution_ut.cpp @@ -856,10 +856,16 @@ extern "C" void prof_ra_cfi_collect(void) { // Named trampoline so Test 3's "caller of the boundary frame" is a specific, // symbolizable function rather than the test body itself. extern "C" __attribute__((noinline)) void prof_ra_cfi_trampoline(void) { - // volatile to defeat tail-call/inlining folding this frame away. - volatile int guard = 1; - (void)guard; prof_ra_cfi_caller(); + // noinline only stops this function being inlined into its caller; at -O3 + // the call above would still become a tail jump, erasing this frame at + // runtime. A volatile store after the call leaves the compiler something + // to do on return, so the call cannot be a tail call and the frame + // survives for the walker to attribute against. A volatile store *before* + // the call does not work -- the compiler emits it and then tears the frame + // down anyway. + volatile int sink = 0; + (void)sink; } #endif // __x86_64__ || __aarch64__ @@ -1027,9 +1033,10 @@ extern "C" void prof_ra_plt_collect(void) { } extern "C" __attribute__((noinline)) void prof_ra_plt_trampoline(void) { - volatile int guard = 1; - (void)guard; prof_ra_plt_caller(); + // Same tail-call guard as prof_ra_cfi_trampoline above. + volatile int sink = 0; + (void)sink; } #endif // __x86_64__ || __aarch64__