]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/static-destruct.h
Merge pull request #28301 from berrange/cvm-lockdown
[thirdparty/systemd.git] / src / basic / static-destruct.h
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
4368277c 2
67e16c31
LP
3#pragma once
4
e30f9c97 5#include "alloc-util.h"
67e16c31 6#include "macro.h"
9695b0c0 7#include "memory-util.h"
67e16c31
LP
8
9/* A framework for registering static variables that shall be freed on shutdown of a process. It's a bit like gcc's
10 * destructor attribute, but allows us to precisely schedule when we want to free the variables. This is supposed to
11 * feel a bit like the gcc cleanup attribute, but for static variables. Note that this does not work for static
12 * variables declared in .so's, as the list is private to the same linking unit. But maybe that's a good thing. */
13
555ead89
YW
14#define _common_static_destruct_attrs_ \
15 /* Older compilers don't know "retain" attribute. */ \
16 _Pragma("GCC diagnostic ignored \"-Wattributes\"") \
17 /* The actual destructor structure we place in a special section to find it. */ \
18 _section_("SYSTEMD_STATIC_DESTRUCT") \
19 /* Use pointer alignment, since that is apparently what gcc does for static variables. */ \
20 _alignptr_ \
21 /* Make sure this is not dropped from the image despite not being explicitly referenced. */ \
22 _used_ \
23 /* Prevent garbage collection by the linker. */ \
24 _retain_ \
25 /* Make sure that AddressSanitizer doesn't pad this variable: we want everything in this section
26 * packed next to each other so that we can enumerate it. */ \
27 _variable_no_sanitize_address_
28
9695b0c0
YW
29typedef enum StaticDestructorType {
30 STATIC_DESTRUCTOR_SIMPLE,
31 STATIC_DESTRUCTOR_ARRAY,
32 _STATIC_DESTRUCTOR_TYPE_MAX,
33 _STATIC_DESTRUCTOR_INVALID = -EINVAL,
34} StaticDestructorType;
35
36typedef struct SimpleCleanup {
67e16c31 37 void *data;
e30f9c97 38 free_func_t destroy;
9695b0c0
YW
39} SimpleCleanup;
40
41typedef struct StaticDestructor {
42 StaticDestructorType type;
43 union {
44 SimpleCleanup simple;
45 ArrayCleanup array;
46 };
67e16c31
LP
47} StaticDestructor;
48
49#define STATIC_DESTRUCTOR_REGISTER(variable, func) \
50 _STATIC_DESTRUCTOR_REGISTER(UNIQ, variable, func)
51
52#define _STATIC_DESTRUCTOR_REGISTER(uq, variable, func) \
53 /* Type-safe destructor */ \
54 static void UNIQ_T(static_destructor_wrapper, uq)(void *p) { \
55 typeof(variable) *q = p; \
56 func(q); \
57 } \
555ead89 58 _common_static_destruct_attrs_ \
67e16c31 59 static const StaticDestructor UNIQ_T(static_destructor_entry, uq) = { \
9695b0c0
YW
60 .type = STATIC_DESTRUCTOR_SIMPLE, \
61 .simple.data = &(variable), \
62 .simple.destroy = UNIQ_T(static_destructor_wrapper, uq), \
67e16c31
LP
63 }
64
9695b0c0
YW
65#define STATIC_ARRAY_DESTRUCTOR_REGISTER(a, n, func) \
66 _STATIC_ARRAY_DESTRUCTOR_REGISTER(UNIQ, a, n, func)
67
68#define _STATIC_ARRAY_DESTRUCTOR_REGISTER(uq, a, n, func) \
69 /* Type-safety check */ \
70 _unused_ static void (* UNIQ_T(static_destructor_wrapper, uq))(typeof(a[0]) *x, size_t y) = (func); \
71 _common_static_destruct_attrs_ \
72 static const StaticDestructor UNIQ_T(static_destructor_entry, uq) = { \
73 .type = STATIC_DESTRUCTOR_ARRAY, \
74 .array.parray = (void**) &(a), \
75 .array.pn = &(n), \
76 .array.pfunc = (free_array_func_t) (func), \
77 };
78
1f568ba1
ZJS
79/* Beginning and end of our section listing the destructors. We define these as weak as we want this to work
80 * even if no destructors are defined and the section is missing. */
555ead89
YW
81extern const StaticDestructor _weak_ __start_SYSTEMD_STATIC_DESTRUCT[];
82extern const StaticDestructor _weak_ __stop_SYSTEMD_STATIC_DESTRUCT[];
67e16c31 83
dfaf16eb
LP
84/* The function to destroy everything. (Note that this must be static inline, as it's key that it remains in
85 * the same linking unit as the variables we want to destroy.) */
67e16c31 86static inline void static_destruct(void) {
67e16c31
LP
87 if (!__start_SYSTEMD_STATIC_DESTRUCT)
88 return;
89
555ead89
YW
90 for (const StaticDestructor *d = ALIGN_PTR(__start_SYSTEMD_STATIC_DESTRUCT);
91 d < __stop_SYSTEMD_STATIC_DESTRUCT;
92 d = ALIGN_PTR(d + 1))
9695b0c0
YW
93 switch (d->type) {
94 case STATIC_DESTRUCTOR_SIMPLE:
95 d->simple.destroy(d->simple.data);
96 break;
97
98 case STATIC_DESTRUCTOR_ARRAY:
99 array_cleanup(&d->array);
100 break;
101
102 default:
103 assert_not_reached();
104 }
67e16c31 105}