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