aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/netbsd-tests/lib/libc/stdlib/h_atexit.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/contrib/netbsd-tests/lib/libc/stdlib/h_atexit.c b/contrib/netbsd-tests/lib/libc/stdlib/h_atexit.c
index b2f91c4c5fe2..d3e1f113abab 100644
--- a/contrib/netbsd-tests/lib/libc/stdlib/h_atexit.c
+++ b/contrib/netbsd-tests/lib/libc/stdlib/h_atexit.c
@@ -42,9 +42,33 @@ __RCSID("$NetBSD: h_atexit.c,v 1.1 2011/01/12 19:44:08 pgoyette Exp $");
extern int __cxa_atexit(void (*func)(void *), void *, void *);
extern void __cxa_finalize(void *);
+#if defined(__FreeBSD__)
+/*
+ * On shared object unload, in __cxa_finalize, call and clear all installed
+ * atexit and __cxa_atexit handlers that are either installed by unloaded
+ * dso, or points to the functions provided by the dso.
+ *
+ * The reason of the change is to ensure that there is no lingering pointers
+ * to the unloaded code after the dlclose(3). It is known reason for infinite
+ * stream of the crash reports for many programs which use loadable modules
+ * and fail to properly clean on module unload. Examples are apache, php,
+ * perl etc.
+ *
+ * You pass the &dso_handle_1 and &dso_handle_2, which points inside the
+ * main binary, to the registration function. The code from r211706,
+ * correctly detects that they are for the main binary, and on the first
+ * call to __cxa_finalize(), which also pass pointer to main binary, all
+ * registered functions from the main binary are executed.
+ */
+
+static void *dso_handle_1 = (void *)1;
+static void *dso_handle_2 = (void *)2;
+static void *dso_handle_3 = (void *)3;
+#else
static int dso_handle_1;
static int dso_handle_2;
static int dso_handle_3;
+#endif
static int arg_1;
static int arg_2;
@@ -167,6 +191,15 @@ main(int argc, char *argv[])
ASSERT(0 == atexit(normal_handler_0));
ASSERT(0 == atexit(normal_handler_1));
+#if defined(__FreeBSD__)
+ ASSERT(0 == __cxa_atexit(cxa_handler_4, &arg_1, dso_handle_1));
+ ASSERT(0 == __cxa_atexit(cxa_handler_5, &arg_1, dso_handle_1));
+ ASSERT(0 == __cxa_atexit(cxa_handler_3, &arg_2, dso_handle_2));
+ ASSERT(0 == __cxa_atexit(cxa_handler_2, &arg_3, dso_handle_3));
+
+ __cxa_finalize(dso_handle_1);
+ __cxa_finalize(dso_handle_2);
+#else
ASSERT(0 == __cxa_atexit(cxa_handler_4, &arg_1, &dso_handle_1));
ASSERT(0 == __cxa_atexit(cxa_handler_5, &arg_1, &dso_handle_1));
ASSERT(0 == __cxa_atexit(cxa_handler_3, &arg_2, &dso_handle_2));
@@ -174,5 +207,6 @@ main(int argc, char *argv[])
__cxa_finalize(&dso_handle_1);
__cxa_finalize(&dso_handle_2);
+#endif
exit(0);
}