Branch data Line data Source code
1 : : #pragma once 2 : : 3 : : #include "alloc-util.h" 4 : : #include "macro.h" 5 : : 6 : : /* A framework for registering static variables that shall be freed on shutdown of a process. It's a bit like gcc's 7 : : * destructor attribute, but allows us to precisely schedule when we want to free the variables. This is supposed to 8 : : * feel a bit like the gcc cleanup attribute, but for static variables. Note that this does not work for static 9 : : * variables declared in .so's, as the list is private to the same linking unit. But maybe that's a good thing. */ 10 : : 11 : : typedef struct StaticDestructor { 12 : : void *data; 13 : : free_func_t destroy; 14 : : } StaticDestructor; 15 : : 16 : : #define STATIC_DESTRUCTOR_REGISTER(variable, func) \ 17 : : _STATIC_DESTRUCTOR_REGISTER(UNIQ, variable, func) 18 : : 19 : : #define _STATIC_DESTRUCTOR_REGISTER(uq, variable, func) \ 20 : : /* Type-safe destructor */ \ 21 : : static void UNIQ_T(static_destructor_wrapper, uq)(void *p) { \ 22 : : typeof(variable) *q = p; \ 23 : : func(q); \ 24 : : } \ 25 : : /* The actual destructor structure we place in a special section to find it */ \ 26 : : _section_("SYSTEMD_STATIC_DESTRUCT") \ 27 : : /* We pick pointer alignment, since that is apparently what gcc does for static variables */ \ 28 : : _alignptr_ \ 29 : : /* Make sure this is not dropped from the image because not explicitly referenced */ \ 30 : : _used_ \ 31 : : /* Make sure that AddressSanitizer doesn't pad this variable: we want everything in this section packed next to each other so that we can enumerate it. */ \ 32 : : _variable_no_sanitize_address_ \ 33 : : static const StaticDestructor UNIQ_T(static_destructor_entry, uq) = { \ 34 : : .data = &(variable), \ 35 : : .destroy = UNIQ_T(static_destructor_wrapper, uq), \ 36 : : } 37 : : 38 : : /* Beginning and end of our section listing the destructors. We define these as weak as we want this to work even if 39 : : * there's not a single destructor is defined in which case the section will be missing. */ 40 : : extern const struct StaticDestructor _weak_ __start_SYSTEMD_STATIC_DESTRUCT[]; 41 : : extern const struct StaticDestructor _weak_ __stop_SYSTEMD_STATIC_DESTRUCT[]; 42 : : 43 : : /* The function to destroy everything. (Note that this must be static inline, as it's key that it remains in the same 44 : : * linking unit as the variables we want to destroy. */ 45 : 1128 : static inline void static_destruct(void) { 46 : : const StaticDestructor *d; 47 : : 48 [ + + ]: 1128 : if (!__start_SYSTEMD_STATIC_DESTRUCT) 49 : 508 : return; 50 : : 51 : 620 : d = ALIGN_TO_PTR(__start_SYSTEMD_STATIC_DESTRUCT, sizeof(void*)); 52 [ + + ]: 4104 : while (d < __stop_SYSTEMD_STATIC_DESTRUCT) { 53 : 3484 : d->destroy(d->data); 54 : 3484 : d = ALIGN_TO_PTR(d + 1, sizeof(void*)); 55 : : } 56 : : }