74 lines · cpp
1// -*- C++ -*-2//===----------------------------------------------------------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10// TODO: Figure out why this fails with Memory Sanitizer.11// XFAIL: msan12 13// This test fails on older llvm, when built with picolibc.14// XFAIL: clang-16 && LIBCXX-PICOLIBC-FIXME15 16#undef NDEBUG17#include <assert.h>18#include <stdlib.h>19#include <unwind.h>20 21#define EXPECTED_NUM_FRAMES 5022#define NUM_FRAMES_UPPER_BOUND 10023 24__attribute__((noinline)) _Unwind_Reason_Code callback(_Unwind_Context *context,25 void *cnt) {26 (void)context;27 int *i = (int *)cnt;28 ++*i;29 if (*i > NUM_FRAMES_UPPER_BOUND) {30 abort();31 }32 return _URC_NO_REASON;33}34 35__attribute__((noinline)) void test_backtrace() {36 int n = 0;37 _Unwind_Backtrace(&callback, &n);38 if (n < EXPECTED_NUM_FRAMES) {39 abort();40 }41}42 43// These functions are effectively the same, but we have to be careful to avoid44// unwanted optimizations that would mess with the number of frames we expect.45// Surprisingly, slapping `noinline` is not sufficient -- we also have to avoid46// writing the function in a way that the compiler can easily spot tail47// recursion.48__attribute__((noinline)) int test1(int i);49__attribute__((noinline)) int test2(int i);50 51__attribute__((noinline)) int test1(int i) {52 if (i == 0) {53 test_backtrace();54 return 0;55 } else {56 return i + test2(i - 1);57 }58}59 60__attribute__((noinline)) int test2(int i) {61 if (i == 0) {62 test_backtrace();63 return 0;64 } else {65 return i + test1(i - 1);66 }67}68 69int main(int, char**) {70 int total = test1(50);71 assert(total == 1275);72 return 0;73}74