xref: /freebsd/lib/libc/tests/stdlib/libatexit/libatexit.cc (revision fa38579f317d5c2ff2926fab9b12ee6d429bd155)
1 /*
2  * Copyright (C) 2025 Kyle Evans <kevans@FreeBSD.org>
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  */
7 
8 #include <unistd.h>
9 
10 static int exit_code = -1;
11 static bool fatal_atexit;
12 
13 extern "C" {
14 	void set_fatal_atexit(bool);
15 	void set_exit_code(int);
16 }
17 
18 void
19 set_fatal_atexit(bool fexit)
20 {
21 	fatal_atexit = fexit;
22 }
23 
24 void
25 set_exit_code(int code)
26 {
27 	exit_code = code;
28 }
29 
30 struct other_object {
31 	~other_object() {
32 
33 		/*
34 		 * In previous versions of our __cxa_atexit handling, we would
35 		 * never actually execute this handler because it's added during
36 		 * ~object() below; __cxa_finalize would never revisit it.  We
37 		 * will allow the caller to configure us to exit with a certain
38 		 * exit code so that it can run us twice: once to ensure we
39 		 * don't crash at the end, and again to make sure the handler
40 		 * actually ran.
41 		 */
42 		if (exit_code != -1)
43 			_exit(exit_code);
44 	}
45 };
46 
47 void
48 create_staticobj()
49 {
50 	static other_object obj;
51 }
52 
53 struct object {
54 	~object() {
55 		/*
56 		 * If we're doing the fatal_atexit behavior (i.e., create an
57 		 * object that will add its own dtor for __cxa_finalize), then
58 		 * we don't exit here.
59 		 */
60 		if (fatal_atexit)
61 			create_staticobj();
62 		else if (exit_code != -1)
63 			_exit(exit_code);
64 	}
65 };
66 
67 static object obj;
68