crt: Improve mingw-w64 _register_thread_local_exe_atexit_callback implementation which is used for msvcrt builds Check that the _register_thread_local_exe_atexit_callback function is not called multiple times. UCRT also disallow to call it multiple times. Improve guard in run_callback to ensure that the callback is not executed more times even if the run_callback is called more times. Add mingw-w64 wrapper around the CRT exit() function which will register the callback via atexit before calling the CRT exit function. This ensures that the CRT exit function would call the callback as the first atexit callback. Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index 61c2b3d..07c050d 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am
@@ -182,6 +182,7 @@ misc/__mingw_mbrtowc_cp.c \ misc/__mingw_wcrtomb_cp.c \ misc/_onexit.c \ + misc/exit.c \ misc/mbrlen.c \ misc/mbrtowc.c \ misc/mbsinit.c \
diff --git a/mingw-w64-crt/lib-common/msvcr120_app.def.in b/mingw-w64-crt/lib-common/msvcr120_app.def.in index 06260ee..6bbbf54 100644 --- a/mingw-w64-crt/lib-common/msvcr120_app.def.in +++ b/mingw-w64-crt/lib-common/msvcr120_app.def.in
@@ -1970,7 +1970,7 @@ F_ARM32(erfcl) ; Can't use long double functions from the CRT on x86 erff F_ARM32(erfl) ; Can't use long double functions from the CRT on x86 -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp exp2 exp2f
diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in index 39ece04..fdf8eb8 100644 --- a/mingw-w64-crt/lib-common/msvcrt.def.in +++ b/mingw-w64-crt/lib-common/msvcrt.def.in
@@ -956,7 +956,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp F_X86_NATIVE(DATA) fabs DATA fclose
diff --git a/mingw-w64-crt/lib32/crtdll.def.in b/mingw-w64-crt/lib32/crtdll.def.in index 154d7ad..5dd3c99 100644 --- a/mingw-w64-crt/lib32/crtdll.def.in +++ b/mingw-w64-crt/lib32/crtdll.def.in
@@ -350,7 +350,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA fabs DATA fclose
diff --git a/mingw-w64-crt/lib32/msvcr100.def.in b/mingw-w64-crt/lib32/msvcr100.def.in index 1db3e07..a08fb20 100644 --- a/mingw-w64-crt/lib32/msvcr100.def.in +++ b/mingw-w64-crt/lib32/msvcr100.def.in
@@ -1672,7 +1672,7 @@ ; If we implement cosh too, we can set it to DATA only. cosh div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA fabs DATA fclose
diff --git a/mingw-w64-crt/lib32/msvcr100d.def.in b/mingw-w64-crt/lib32/msvcr100d.def.in index 9899fe0..6939f0d 100644 --- a/mingw-w64-crt/lib32/msvcr100d.def.in +++ b/mingw-w64-crt/lib32/msvcr100d.def.in
@@ -1738,7 +1738,7 @@ cos DATA ; overwritten cosh div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA ; overwritten fabs DATA ; overwritten fclose
diff --git a/mingw-w64-crt/lib32/msvcr110.def.in b/mingw-w64-crt/lib32/msvcr110.def.in index 1a4db81..9a7f16f 100644 --- a/mingw-w64-crt/lib32/msvcr110.def.in +++ b/mingw-w64-crt/lib32/msvcr110.def.in
@@ -1804,7 +1804,7 @@ cos DATA cosh ; If we implement cosh, we can set it to DATA only. div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA fabs DATA fclose
diff --git a/mingw-w64-crt/lib32/msvcr110d.def.in b/mingw-w64-crt/lib32/msvcr110d.def.in index 0b52690..bf4ba2d 100644 --- a/mingw-w64-crt/lib32/msvcr110d.def.in +++ b/mingw-w64-crt/lib32/msvcr110d.def.in
@@ -1871,7 +1871,7 @@ cos DATA ; overwritten cosh div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA ; overwritten fabs DATA ; overwritten fclose
diff --git a/mingw-w64-crt/lib32/msvcr120.def.in b/mingw-w64-crt/lib32/msvcr120.def.in index af88bbb..43ae5cb 100644 --- a/mingw-w64-crt/lib32/msvcr120.def.in +++ b/mingw-w64-crt/lib32/msvcr120.def.in
@@ -1943,7 +1943,7 @@ ; erfcl ; Can't use long double functions from the CRT on x86 erff ; erfl ; Can't use long double functions from the CRT on x86 -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp exp2 exp2f
diff --git a/mingw-w64-crt/lib32/msvcr120d.def.in b/mingw-w64-crt/lib32/msvcr120d.def.in index b8d4c9b..df3d1a0 100644 --- a/mingw-w64-crt/lib32/msvcr120d.def.in +++ b/mingw-w64-crt/lib32/msvcr120d.def.in
@@ -2010,7 +2010,7 @@ ; erfcl ; Can't use long double functions from the CRT on x86 erff ; erfl ; Can't use long double functions from the CRT on x86 -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp exp2 exp2f
diff --git a/mingw-w64-crt/lib32/msvcr40d.def.in b/mingw-w64-crt/lib32/msvcr40d.def.in index aced5b3..bcf0e6a 100644 --- a/mingw-w64-crt/lib32/msvcr40d.def.in +++ b/mingw-w64-crt/lib32/msvcr40d.def.in
@@ -1475,7 +1475,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp fabs fclose
diff --git a/mingw-w64-crt/lib32/msvcr70.def.in b/mingw-w64-crt/lib32/msvcr70.def.in index 53e2bfe..1c44a28 100644 --- a/mingw-w64-crt/lib32/msvcr70.def.in +++ b/mingw-w64-crt/lib32/msvcr70.def.in
@@ -725,7 +725,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp fabs fclose
diff --git a/mingw-w64-crt/lib32/msvcr70d.def.in b/mingw-w64-crt/lib32/msvcr70d.def.in index 7784d76..1eb2a6c 100644 --- a/mingw-w64-crt/lib32/msvcr70d.def.in +++ b/mingw-w64-crt/lib32/msvcr70d.def.in
@@ -769,7 +769,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp fabs fclose
diff --git a/mingw-w64-crt/lib32/msvcr71.def.in b/mingw-w64-crt/lib32/msvcr71.def.in index aa33cd3..576109f 100644 --- a/mingw-w64-crt/lib32/msvcr71.def.in +++ b/mingw-w64-crt/lib32/msvcr71.def.in
@@ -719,7 +719,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp fabs fclose
diff --git a/mingw-w64-crt/lib32/msvcr71d.def.in b/mingw-w64-crt/lib32/msvcr71d.def.in index a317d1e..f64aaa0 100644 --- a/mingw-w64-crt/lib32/msvcr71d.def.in +++ b/mingw-w64-crt/lib32/msvcr71d.def.in
@@ -763,7 +763,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp fabs fclose
diff --git a/mingw-w64-crt/lib32/msvcr80.def.in b/mingw-w64-crt/lib32/msvcr80.def.in index 7d57998..2153e69 100644 --- a/mingw-w64-crt/lib32/msvcr80.def.in +++ b/mingw-w64-crt/lib32/msvcr80.def.in
@@ -1312,7 +1312,7 @@ cos DATA cosh ; If we implement cosh, we can set it to DATA only. div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA fabs DATA fclose
diff --git a/mingw-w64-crt/lib32/msvcr80d.def.in b/mingw-w64-crt/lib32/msvcr80d.def.in index d4deb17..3597f3a 100644 --- a/mingw-w64-crt/lib32/msvcr80d.def.in +++ b/mingw-w64-crt/lib32/msvcr80d.def.in
@@ -1395,7 +1395,7 @@ cos DATA ; overwritten cosh div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA ; overwritten fabs DATA ; overwritten fclose
diff --git a/mingw-w64-crt/lib32/msvcr90.def.in b/mingw-w64-crt/lib32/msvcr90.def.in index a6f5752..5c4c9c2 100644 --- a/mingw-w64-crt/lib32/msvcr90.def.in +++ b/mingw-w64-crt/lib32/msvcr90.def.in
@@ -1306,7 +1306,7 @@ ; If we have cosh implementation, we can set it to DATA only. cosh div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA fabs DATA fclose
diff --git a/mingw-w64-crt/lib32/msvcr90d.def.in b/mingw-w64-crt/lib32/msvcr90d.def.in index eb4f68e..f636d34 100644 --- a/mingw-w64-crt/lib32/msvcr90d.def.in +++ b/mingw-w64-crt/lib32/msvcr90d.def.in
@@ -1378,7 +1378,7 @@ ; If we implement cosh too, we can set it to DATA only. cosh div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA fabs DATA fclose
diff --git a/mingw-w64-crt/lib32/msvcrt10.def.in b/mingw-w64-crt/lib32/msvcrt10.def.in index 8a7d408..4ba98bf 100644 --- a/mingw-w64-crt/lib32/msvcrt10.def.in +++ b/mingw-w64-crt/lib32/msvcrt10.def.in
@@ -1126,7 +1126,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp fabs fclose
diff --git a/mingw-w64-crt/lib32/msvcrt20.def.in b/mingw-w64-crt/lib32/msvcrt20.def.in index 8a87561..ee35087 100644 --- a/mingw-w64-crt/lib32/msvcrt20.def.in +++ b/mingw-w64-crt/lib32/msvcrt20.def.in
@@ -1343,7 +1343,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp fabs fclose
diff --git a/mingw-w64-crt/lib32/msvcrt40.def.in b/mingw-w64-crt/lib32/msvcrt40.def.in index 4c698c1..6347304 100644 --- a/mingw-w64-crt/lib32/msvcrt40.def.in +++ b/mingw-w64-crt/lib32/msvcrt40.def.in
@@ -1443,7 +1443,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp fabs fclose
diff --git a/mingw-w64-crt/lib32/msvcrtd.def.in b/mingw-w64-crt/lib32/msvcrtd.def.in index ea0c17c..130113d 100644 --- a/mingw-w64-crt/lib32/msvcrtd.def.in +++ b/mingw-w64-crt/lib32/msvcrtd.def.in
@@ -669,7 +669,7 @@ ctime difftime div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp fabs fclose
diff --git a/mingw-w64-crt/lib64/msvcr100.def.in b/mingw-w64-crt/lib64/msvcr100.def.in index 2e7991c..b082f74 100644 --- a/mingw-w64-crt/lib64/msvcr100.def.in +++ b/mingw-w64-crt/lib64/msvcr100.def.in
@@ -1624,7 +1624,7 @@ cosh coshf DATA div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA expf DATA fabs DATA
diff --git a/mingw-w64-crt/lib64/msvcr100d.def.in b/mingw-w64-crt/lib64/msvcr100d.def.in index 26c568d..b737e02 100644 --- a/mingw-w64-crt/lib64/msvcr100d.def.in +++ b/mingw-w64-crt/lib64/msvcr100d.def.in
@@ -1689,7 +1689,7 @@ cosh coshf DATA ; overwritten div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA ; overwritten expf DATA ; overwritten fabs DATA ; overwritten
diff --git a/mingw-w64-crt/lib64/msvcr110.def.in b/mingw-w64-crt/lib64/msvcr110.def.in index 83362bc..9df2ee9 100644 --- a/mingw-w64-crt/lib64/msvcr110.def.in +++ b/mingw-w64-crt/lib64/msvcr110.def.in
@@ -1748,7 +1748,7 @@ cosh coshf div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp expf fabs
diff --git a/mingw-w64-crt/lib64/msvcr110d.def.in b/mingw-w64-crt/lib64/msvcr110d.def.in index 6217687..c657ad6 100644 --- a/mingw-w64-crt/lib64/msvcr110d.def.in +++ b/mingw-w64-crt/lib64/msvcr110d.def.in
@@ -1813,7 +1813,7 @@ cosh coshf div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp expf fabs
diff --git a/mingw-w64-crt/lib64/msvcr120.def.in b/mingw-w64-crt/lib64/msvcr120.def.in index 9095011..130f10f 100644 --- a/mingw-w64-crt/lib64/msvcr120.def.in +++ b/mingw-w64-crt/lib64/msvcr120.def.in
@@ -1886,7 +1886,7 @@ ; erfcl ; Can't use long double functions from the CRT on x86 erff ; erfl ; Can't use long double functions from the CRT on x86 -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp exp2 exp2f
diff --git a/mingw-w64-crt/lib64/msvcr120d.def.in b/mingw-w64-crt/lib64/msvcr120d.def.in index 31c3258..278ec14 100644 --- a/mingw-w64-crt/lib64/msvcr120d.def.in +++ b/mingw-w64-crt/lib64/msvcr120d.def.in
@@ -1951,7 +1951,7 @@ ; erfcl ; Can't use long double functions from the CRT on x86 erff ; erfl ; Can't use long double functions from the CRT on x86 -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp exp2 exp2f
diff --git a/mingw-w64-crt/lib64/msvcr80.def.in b/mingw-w64-crt/lib64/msvcr80.def.in index f81f10e..a46fbae 100644 --- a/mingw-w64-crt/lib64/msvcr80.def.in +++ b/mingw-w64-crt/lib64/msvcr80.def.in
@@ -1247,7 +1247,7 @@ cosh coshf div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA expf DATA fabs
diff --git a/mingw-w64-crt/lib64/msvcr80d.def.in b/mingw-w64-crt/lib64/msvcr80d.def.in index 3fbac94..dc2ece7 100644 --- a/mingw-w64-crt/lib64/msvcr80d.def.in +++ b/mingw-w64-crt/lib64/msvcr80d.def.in
@@ -1324,7 +1324,7 @@ cosh coshf div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA ; overwritten expf DATA ; overwritten fabs
diff --git a/mingw-w64-crt/lib64/msvcr90.def.in b/mingw-w64-crt/lib64/msvcr90.def.in index 3efea26..2282832 100644 --- a/mingw-w64-crt/lib64/msvcr90.def.in +++ b/mingw-w64-crt/lib64/msvcr90.def.in
@@ -1244,7 +1244,7 @@ cosh coshf DATA div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA expf DATA fabs DATA
diff --git a/mingw-w64-crt/lib64/msvcr90d.def.in b/mingw-w64-crt/lib64/msvcr90d.def.in index c95a741..5bdfa14 100644 --- a/mingw-w64-crt/lib64/msvcr90d.def.in +++ b/mingw-w64-crt/lib64/msvcr90d.def.in
@@ -1310,7 +1310,7 @@ cosh coshf div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp DATA expf DATA fabs
diff --git a/mingw-w64-crt/libarm32/msvcr110.def.in b/mingw-w64-crt/libarm32/msvcr110.def.in index 3c067e0..4decd8f 100644 --- a/mingw-w64-crt/libarm32/msvcr110.def.in +++ b/mingw-w64-crt/libarm32/msvcr110.def.in
@@ -1734,7 +1734,7 @@ cosh coshf div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp expf fabs
diff --git a/mingw-w64-crt/libarm32/msvcr110d.def.in b/mingw-w64-crt/libarm32/msvcr110d.def.in index 7164dbb..81fc746 100644 --- a/mingw-w64-crt/libarm32/msvcr110d.def.in +++ b/mingw-w64-crt/libarm32/msvcr110d.def.in
@@ -1799,7 +1799,7 @@ cosh coshf div -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp expf fabs
diff --git a/mingw-w64-crt/libarm32/msvcr120.def.in b/mingw-w64-crt/libarm32/msvcr120.def.in index 8e3b65f..2baa561 100644 --- a/mingw-w64-crt/libarm32/msvcr120.def.in +++ b/mingw-w64-crt/libarm32/msvcr120.def.in
@@ -1853,7 +1853,7 @@ erfcl erff erfl -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp exp2 exp2f
diff --git a/mingw-w64-crt/libarm32/msvcr120d.def.in b/mingw-w64-crt/libarm32/msvcr120d.def.in index ef27891..afd9d45 100644 --- a/mingw-w64-crt/libarm32/msvcr120d.def.in +++ b/mingw-w64-crt/libarm32/msvcr120d.def.in
@@ -1918,7 +1918,7 @@ erfcl erff erfl -exit +__msvcrt_exit DATA == exit ; mingw-w64 provides exit() function as wrapper around renamed __msvcrt_exit symbol exp exp2 exp2f
diff --git a/mingw-w64-crt/misc/exit.c b/mingw-w64-crt/misc/exit.c new file mode 100644 index 0000000..88e1b3a --- /dev/null +++ b/mingw-w64-crt/misc/exit.c
@@ -0,0 +1,21 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include <stdlib.h> + +void (__cdecl *__mingw_prepare_thread_local_exe_atexit_callback_ptr)(void) __attribute__((common)); /* tentative */ +extern void (__cdecl *__MINGW_IMP_SYMBOL(__msvcrt_exit))(int code) __MINGW_ATTRIB_NORETURN; + +__MINGW_ATTRIB_NORETURN void __cdecl exit(int code) +{ + /* __mingw_prepare_thread_local_exe_atexit_callback_ptr is thread safe and + * also can be called multiple times. Registration is done under CRT lock + * and execution of the registered callback is done exactly once. */ + if (__mingw_prepare_thread_local_exe_atexit_callback_ptr) + __mingw_prepare_thread_local_exe_atexit_callback_ptr(); + __MINGW_IMP_SYMBOL(__msvcrt_exit)(code); +} +typeof(exit) *__MINGW_IMP_SYMBOL(exit) = exit;
diff --git a/mingw-w64-crt/misc/register_tls_atexit.c b/mingw-w64-crt/misc/register_tls_atexit.c index 09d9270..1875a67 100644 --- a/mingw-w64-crt/misc/register_tls_atexit.c +++ b/mingw-w64-crt/misc/register_tls_atexit.c
@@ -5,25 +5,42 @@ */ #include <process.h> -#include <windows.h> -#include <winnt.h> #include <stdlib.h> +#include <internal.h> static _tls_callback_type callback; -static void run_callback(void) +static void __cdecl run_callback(void) { + /* Ensure that callback is called only once. */ + static int called = 0; + if (called) + return; + called = 1; if (callback) callback(NULL, DLL_PROCESS_DETACH, 0); - callback = NULL; } +/* mingw-w64 exit() wrapper calls this function pointer prior CRT atexit() call + * to ensure that the registered callback is called before any other callback. + * If some other code calls the exported exit DLL function directly then the + * atexit() call inside _register_thread_local_exe_atexit_callback guarantees + * at least that the callback is called (but does not have to as a first one). */ +static void __cdecl set_atexit_callback(void) +{ + atexit(run_callback); +} +void (__cdecl *__mingw_prepare_thread_local_exe_atexit_callback_ptr)(void) = set_atexit_callback; + void __cdecl _register_thread_local_exe_atexit_callback(_tls_callback_type cb) { + /* _register_thread_local_exe_atexit_callback cannot be called multiple times. */ + if (callback) + _amsg_exit(10); /* _RT_ABORT */ callback = cb; /* This should guarantee that the callback is called. It won't be run in the * exact right spot as intended to, but it will be run. */ - atexit(run_callback); + set_atexit_callback(); } typeof(_register_thread_local_exe_atexit_callback) *__MINGW_IMP_SYMBOL(_register_thread_local_exe_atexit_callback) = _register_thread_local_exe_atexit_callback;