crt: test: Add new t_tls_exe_dtor_atexit_order test which verifies order of atexit and __tlregdtor callbacks

The __tlregdtor 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 6cfa3f8..f80fdce 100644
--- a/mingw-w64-crt/testcases/Makefile.am
+++ b/mingw-w64-crt/testcases/Makefile.am
@@ -140,6 +140,7 @@
   t_tls_dll_native \
   t_tls_dll_native_process_detach \
   t_tls_exe_dtor \
+  t_tls_exe_dtor_atexit_order \
   t_tls_exe_dyn \
   t_tls_exe_native \
   t_tls_exe_native_process_detach \
diff --git a/mingw-w64-crt/testcases/t_tls_exe_dtor_atexit_order.c b/mingw-w64-crt/testcases/t_tls_exe_dtor_atexit_order.c
new file mode 100644
index 0000000..6554ae3
--- /dev/null
+++ b/mingw-w64-crt/testcases/t_tls_exe_dtor_atexit_order.c
@@ -0,0 +1,65 @@
+#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 __cdecl __tlregdtor(void (__cdecl*func)(void));
+
+static int main_success = 0;
+
+static void __cdecl atexit1_callback(void)
+{
+  printf("Error: atexit1 calllback was called before __tlregdtor 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 __tlregdtor callback\n");
+  /* exit, _exit, or ExitProcess calls TLS callbacks, so use TerminateProcess() which is not calling them */
+  TerminateProcess(GetCurrentProcess(), 1);
+}
+
+static void __cdecl dtor_callback(void)
+{
+  printf("SUCCESS: __tlregdtor 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 __tlregdtor() call and one after __tlregdtor() call.
+   * The __tlregdtor 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 (__tlregdtor(&dtor_callback) != 0) {
+    printf("Error: __tlregdtor() 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 __tlregdtor callback would be called before all atexit callbacks...\n");
+  main_success = 1;
+  return 1; /* __tlregdtor callback changes return code to 0 */
+}