crt: test: Add new t_tls_exe_cxa_atexit_order test which verifies order of atexit and mingw_cxa_atexit callbacks The mingw_cxa_atexit callback must be called before any atexit callback independently of the registration order. Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-crt/testcases/Makefile.am b/mingw-w64-crt/testcases/Makefile.am index f80fdce..8459e28 100644 --- a/mingw-w64-crt/testcases/Makefile.am +++ b/mingw-w64-crt/testcases/Makefile.am
@@ -139,6 +139,7 @@ t_tls_dll \ t_tls_dll_native \ t_tls_dll_native_process_detach \ + t_tls_exe_cxa_atexit_order \ t_tls_exe_dtor \ t_tls_exe_dtor_atexit_order \ t_tls_exe_dyn \
diff --git a/mingw-w64-crt/testcases/t_tls_exe_cxa_atexit_order.c b/mingw-w64-crt/testcases/t_tls_exe_cxa_atexit_order.c new file mode 100644 index 0000000..003b212 --- /dev/null +++ b/mingw-w64-crt/testcases/t_tls_exe_cxa_atexit_order.c
@@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +/* mingw-w64 headers */ +#include "libtest.h" + +extern int __mingw_cxa_atexit(void (__thiscall *dtor)(void *obj), void *obj, void *dso); + +static int main_success = 0; + +static void __cdecl atexit1_callback(void) +{ + printf("Error: atexit1 calllback was called before mingw_cxa_atexit callback\n"); + /* exit, _exit, or ExitProcess calls TLS callbacks, so use TerminateProcess() which is not calling them */ + TerminateProcess(GetCurrentProcess(), 1); +} + +static void __cdecl atexit2_callback(void) +{ + printf("Error: atexit2 calllback was called before mingw_cxa_atexit callback\n"); + /* exit, _exit, or ExitProcess calls TLS callbacks, so use TerminateProcess() which is not calling them */ + TerminateProcess(GetCurrentProcess(), 1); +} + +static void __thiscall mingw_cxa_atexit_callback(void *obj) +{ + if (obj != (void*)42) { + printf("Error: mingw_cxa_atexit callback was called with wrong obj\n"); + main_success = 0; + } else { + printf("SUCCESS: mingw_cxa_atexit callback was called\n"); + } + /* exit, _exit, or ExitProcess calls TLS callbacks, so use TerminateProcess() which is not calling them */ + TerminateProcess(GetCurrentProcess(), main_success ? 0 : 1); +} + +int main(void) +{ + mingw_test_init(); + + /* Register two atexit callbacks, one before __mingw_cxa_atexit() call and one after __mingw_cxa_atexit() call. + * The mingw_cxa_atexit callback must be called before any atexit callback independently of the registration order. */ + + if (atexit(atexit1_callback) != 0) { + printf("Error: atexit() failed\n"); + /* exit, _exit, or ExitProcess calls TLS callbacks, so use TerminateProcess() which is not calling them */ + TerminateProcess(GetCurrentProcess(), 1); + } + + if (__mingw_cxa_atexit(&mingw_cxa_atexit_callback, (void*)42, NULL) != 0) { + printf("Error: __mingw_cxa_atexit() failed\n"); + /* exit, _exit, or ExitProcess calls TLS callbacks, so use TerminateProcess() which is not calling them */ + TerminateProcess(GetCurrentProcess(), 1); + } + + if (atexit(atexit2_callback) != 0) { + printf("Error: atexit() failed\n"); + /* exit, _exit, or ExitProcess calls TLS callbacks, so use TerminateProcess() which is not calling them */ + TerminateProcess(GetCurrentProcess(), 1); + } + + printf("Checking if the mingw_cxa_atexit callback would be called before all atexit callbacks...\n"); + main_success = 1; + return 1; /* mingw_cxa_atexit callback changes return code to 0 */ +}