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 */
+}