1 //===-- Unittests for atexit ----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "src/__support/CPP/Array.h" 10 #include "src/__support/CPP/Utility.h" 11 #include "src/stdlib/atexit.h" 12 #include "src/stdlib/exit.h" 13 #include "utils/UnitTest/Test.h" 14 15 static int a; 16 TEST(LlvmLibcAtExit, Basic) { 17 // In case tests ever run multiple times. 18 a = 0; 19 20 auto test = [] { 21 int status = __llvm_libc::atexit(+[] { 22 if (a != 1) 23 __builtin_trap(); 24 }); 25 status |= __llvm_libc::atexit(+[] { a++; }); 26 if (status) 27 __builtin_trap(); 28 29 __llvm_libc::exit(0); 30 }; 31 EXPECT_EXITS(test, 0); 32 } 33 34 TEST(LlvmLibcAtExit, AtExitCallsSysExit) { 35 auto test = [] { 36 __llvm_libc::atexit(+[] { _Exit(1); }); 37 __llvm_libc::exit(0); 38 }; 39 EXPECT_EXITS(test, 1); 40 } 41 42 static int size; 43 static __llvm_libc::cpp::Array<int, 256> arr; 44 45 template <int... Ts> 46 void register_atexit_handlers(__llvm_libc::cpp::IntegerSequence<int, Ts...>) { 47 (__llvm_libc::atexit(+[] { arr[size++] = Ts; }), ...); 48 } 49 50 template <int count> constexpr auto getTest() { 51 return [] { 52 __llvm_libc::atexit(+[] { 53 if (size != count) 54 __builtin_trap(); 55 for (int i = 0; i < count; i++) 56 if (arr[i] != count - 1 - i) 57 __builtin_trap(); 58 }); 59 register_atexit_handlers( 60 __llvm_libc::cpp::MakeIntegerSequence<int, count>{}); 61 __llvm_libc::exit(0); 62 }; 63 } 64 65 TEST(LlvmLibcAtExit, ReverseOrder) { 66 // In case tests ever run multiple times. 67 size = 0; 68 69 auto test = getTest<32>(); 70 EXPECT_EXITS(test, 0); 71 } 72 73 TEST(LlvmLibcAtExit, Many) { 74 // In case tests ever run multiple times. 75 size = 0; 76 77 auto test = getTest<256>(); 78 EXPECT_EXITS(test, 0); 79 } 80 81 // POSIX doesn't specify if an atexit handler can call atexit, it only says it 82 // is undefined for a handler to call exit(3). The current implementation will 83 // end up invoking the newly registered function, although glibc does, other 84 // libc's do not. This just tests that we don't deadlock when an exit handler 85 // calls atexit. 86 TEST(LlvmLibcAtExit, HandlerCallsAtExit) { 87 auto test = [] { 88 __llvm_libc::atexit(+[] { 89 __llvm_libc::atexit(+[] { __builtin_trap(); }); 90 __llvm_libc::exit(0); 91 }); 92 }; 93 EXPECT_EXITS(test, 0); 94 } 95