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