From c3b7b56dd0345b155d8b98c01eca62b791eb6d45 Mon Sep 17 00:00:00 2001 From: Colin Vidal Date: Thu, 4 Dec 2025 14:02:01 +0100 Subject: [PATCH] document usage of BIND9 constructors/destructors Document the way `__attribute__((__constructor__))` and `__attribute__((__destructor__))` must be used in BIND9 libraries in order to avoid unexpected behaviors with other third-party libraries. --- lib/dns/include/dns/lib.h | 4 ++++ lib/isc/include/isc/lib.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/lib/dns/include/dns/lib.h b/lib/dns/include/dns/lib.h index cb88744bbe..9cf053a7c2 100644 --- a/lib/dns/include/dns/lib.h +++ b/lib/dns/include/dns/lib.h @@ -11,6 +11,10 @@ * information regarding copyright ownership. */ +/* + * See `lib/isc/include/isc/lib.h` README + */ + #pragma once #include diff --git a/lib/isc/include/isc/lib.h b/lib/isc/include/isc/lib.h index ee918e7899..412dd9746d 100644 --- a/lib/isc/include/isc/lib.h +++ b/lib/isc/include/isc/lib.h @@ -11,6 +11,34 @@ * information regarding copyright ownership. */ +/* + * BIND9 constructor/destructor README + * ----------------------------------- + * + * A function tagged with `__attribute__((__destructor__))` is called right + * after `main()` returns (or `exit()` is called; see `man atexit` for more + * details). However is a valid assumption _only_ if the function is defined + * inside the binary. + * + * If the function is defined as part of a shared library, it will + * be called only when the library is unloaded by the OS linker. There is no + * way to control the order in which two destructor functions "A" and "B" are + * called if they are defined in separate libraries, because it depends + * on the order in which the OS linker unloads the libraries. + * + * As a consequence, all contructor/destructor functions of BIND9 must be + * defined in `lib//include//lib.h` header and such header must be + * included in each binaries (in each C file defining `main()`) and must not be + * included in any library. + * + * Otherwise, there might be interference. For example, LSAN which could run + * before the BIND9 destructor functions have cleaned up remaining non-root + * memory. + * + * The order of the calls between the BIND9 constructors/destructors is enforced + * by a reference counter in the `__lib_{initialize,shutdown}` functions. + */ + #pragma once #include