Re: [Mingw-w64-public] [PATCH] crt: Unify and simplify handling of constructor/destructor lists
On Fri, 3 Aug 2018, Liu Hao wrote: 在 2018-08-03 03:16, Martin Storsjö 写道: GNU binutils ld traditionally provides __CTOR_LIST__ and __DTOR_LIST__ symbols via a linker script, while lld doesn't. (... ...) -#else -// old method that iterates the list twice because old linker scripts do not have __CTOR_END__ This drops the compatibility with those 'old linker scripts', doesn't it? No, it's still compatible - we provide our own __CTOR_END__ anyway, which is sorted in the right place by the linker due to the section name. In practice this comment seemed to be a bit misleading, because not even the latest binutils provide __CTOR_END__. It does store the terminating null pointer here, but it doesn't provide any symbol pointing to it. // Martin -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] Error Codes Patch
在 2018/8/3 1:10, Tom Ritter 写道: > Hit an error compiling Firefox because 1471 wasn't defined. > > -tom > Thanks for the patch. Pushed to master. LRN: He was talking about the value of `ERROR_NOT_GUI_PROCESS` in the patch attached. -- Best regards, LH_Mouse -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH] crt: Unify and simplify handling of constructor/destructor lists
在 2018-08-03 03:16, Martin Storsjö 写道: > GNU binutils ld traditionally provides __CTOR_LIST__ and __DTOR_LIST__ > symbols via a linker script, while lld doesn't. > (... ...) > -#else > -// old method that iterates the list twice because old linker scripts do not > have __CTOR_END__ This drops the compatibility with those 'old linker scripts', doesn't it? This patch looks good otherwise. -- Best regards, LH_Mouse -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH] crt: Unify and simplify handling of constructor/destructor lists
On 08/02/2018 08:25 PM, Martin Storsjö wrote: > On Thu, 2 Aug 2018, Liu Hao wrote: > >>> index 54cbf02..44ff653 100644 >>> --- a/mingw-w64-crt/crt/gccmain.c >>> +++ b/mingw-w64-crt/crt/gccmain.c >>> @@ -23,18 +23,24 @@ __do_global_dtors (void) >>> while (*p) >>> { >>> - (*(p)) (); >>> + // If the linker provided its own __DTOR_LIST__ in addition to >>> the >>> + // one we provide, we'd end up with the first pointer here being >>> + // a (func_ptr)-1 sentinel. >> >> jon_y used to require all comments be C89-ish. I am not totally clear >> about the reason. May he elaborate a little. > > I forgot to change this for this patch when I posted the updated > version, but I changed it for the cxa_atexit patchset before pushing. > > // Martin > > It's a preference, but not a hard one, seeing though C89 style comments are supported by all C compliant compilers. signature.asc Description: OpenPGP digital signature -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH] crt: Unify and simplify handling of constructor/destructor lists
On Thu, 2 Aug 2018, Liu Hao wrote: index 54cbf02..44ff653 100644 --- a/mingw-w64-crt/crt/gccmain.c +++ b/mingw-w64-crt/crt/gccmain.c @@ -23,18 +23,24 @@ __do_global_dtors (void) while (*p) { - (*(p)) (); + // If the linker provided its own __DTOR_LIST__ in addition to the + // one we provide, we'd end up with the first pointer here being + // a (func_ptr)-1 sentinel. jon_y used to require all comments be C89-ish. I am not totally clear about the reason. May he elaborate a little. I forgot to change this for this patch when I posted the updated version, but I changed it for the cxa_atexit patchset before pushing. // Martin -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCHv2 1/4] crt: Add an implementation of __cxa_atexit and __cxa_thread_atexit
On Thu, 2 Aug 2018, Liu Hao wrote: 在 2018/8/2 19:22, Martin Storsjö 写道: + +typedef void (__thiscall * dtor)(void*); +int __cxa_atexit(dtor dtor, void *obj, void *dso); +int __cxa_thread_atexit(dtor dtor, void *obj, void *dso); + +typedef struct dtor_obj dtor_obj; +struct dtor_obj { + dtor dtor; It is a bit strange to see the same identifier be repeated here. I suggest you rename the typedef to `dtor_fn` or `dtor_proc`. Renamed the typedef to dtor_fn These 4 patches look good to me. Thanks for the thorough review! Pushed. // Martin -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH] crt: Unify and simplify handling of constructor/destructor lists
On Thu, 2 Aug 2018, Martin Storsjö wrote: On Thu, 2 Aug 2018, Liu Hao wrote: 在 2018/8/2 19:02, Martin Storsjö 写道: -#ifdef __clang__ extern func_ptr __CTOR_END__[]; extern func_ptr __DTOR_END__[]; void __do_global_ctors (void) { static func_ptr *p = __CTOR_END__ - 1; + // If the linker provided its own __CTOR_LIST__ in addition to the one + // we provide, we'd actually stop at __CTOR_LIST__+1, but that's no problem + // for this function. while (*p != (func_ptr) -1) { (*(p))(); At the very firsts iteration, isn't `*p` null if there are two null termini in the list? (i.e. the list looks like `-1, -1, ... some `func_ptr`s ... , 0, 0`) I thought the same; that's why I did the extra check with "if (*p)", as I mentioned in the other mail. However, in practice, __CTOR_END__ points to the first 0-terminator. Not sure why that is, but you can check with -Wl,-Map,map.txt. But yes, it's safer with that extra check added, then both iterations should be fine, regardless which one the symbol points to, in both ends. This is because it seems like GNU LD actually never provides any __CTOR_END__ symbol. But we can have the extra check in any case, for safety and symmetry. // Martin -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] Error Codes Patch
On 02.08.2018 20:10, Tom Ritter wrote: > Hit an error compiling Firefox because 1471 wasn't defined. Add more context here because 1471 doesn't ring a bell. signature.asc Description: OpenPGP digital signature -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
[Mingw-w64-public] Error Codes Patch
Hit an error compiling Firefox because 1471 wasn't defined. -tom From 71ee4edf14d76ddacb8154620024c7a8b60be18b Mon Sep 17 00:00:00 2001 From: Tom Ritter Date: Thu, 2 Aug 2018 09:50:56 -0500 Subject: [PATCH] Add Error Codes between 1460 and 1471 --- mingw-w64-headers/include/winerror.h| 9 + mingw-w64-tools/widl/include/winerror.h | 1 + 2 files changed, 10 insertions(+) mode change 100644 => 100755 mingw-w64-headers/include/winerror.h diff --git a/mingw-w64-headers/include/winerror.h b/mingw-w64-headers/include/winerror.h old mode 100644 new mode 100755 index e117b046..5eba03f6 --- a/mingw-w64-headers/include/winerror.h +++ b/mingw-w64-headers/include/winerror.h @@ -631,6 +631,15 @@ #define ERROR_TIMEOUT __MSABI_LONG(1460) #define ERROR_INVALID_MONITOR_HANDLE __MSABI_LONG(1461) #define ERROR_INCORRECT_SIZE __MSABI_LONG(1462) +#define ERROR_SYMLINK_CLASS_DISABLED __MSABI_LONG(1463) +#define ERROR_SYMLINK_NOT_SUPPORTED __MSABI_LONG(1464) +#define ERROR_XML_PARSE_ERROR __MSABI_LONG(1465) +#define ERROR_XMLDSIG_ERROR __MSABI_LONG(1466) +#define ERROR_RESTART_APPLICATION __MSABI_LONG(1467) +#define ERROR_WRONG_COMPARTMENT __MSABI_LONG(1468) +#define ERROR_AUTHIP_FAILURE __MSABI_LONG(1469) +#define ERROR_NO_NVRAM_RESOURCES __MSABI_LONG(1470) +#define ERROR_NOT_GUI_PROCESS __MSABI_LONG(1471) #define ERROR_EVENTLOG_FILE_CORRUPT __MSABI_LONG(1500) #define ERROR_EVENTLOG_CANT_START __MSABI_LONG(1501) #define ERROR_LOG_FILE_FULL __MSABI_LONG(1502) diff --git a/mingw-w64-tools/widl/include/winerror.h b/mingw-w64-tools/widl/include/winerror.h index 2c6ce20b..180e3efe 100644 --- a/mingw-w64-tools/widl/include/winerror.h +++ b/mingw-w64-tools/widl/include/winerror.h @@ -940,6 +940,7 @@ static inline HRESULT HRESULT_FROM_WIN32(unsigned int x) #define ERROR_WRONG_COMPARTMENT1468 #define ERROR_AUTHIP_FAILURE 1469 #define ERROR_NO_NVRAM_RESOURCES 1470 +#define ERROR_NOT_GUI_PROCESS 1471 #define ERROR_EVENTLOG_FILE_CORRUPT1500 #define ERROR_EVENTLOG_CANT_START 1501 #define ERROR_LOG_FILE_FULL1502 -- 2.17.1 -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH] crt: Unify and simplify handling of constructor/destructor lists
On Thu, 2 Aug 2018, Liu Hao wrote: 在 2018/8/2 19:02, Martin Storsjö 写道: -#ifdef __clang__ extern func_ptr __CTOR_END__[]; extern func_ptr __DTOR_END__[]; void __do_global_ctors (void) { static func_ptr *p = __CTOR_END__ - 1; + // If the linker provided its own __CTOR_LIST__ in addition to the one + // we provide, we'd actually stop at __CTOR_LIST__+1, but that's no problem + // for this function. while (*p != (func_ptr) -1) { (*(p))(); At the very firsts iteration, isn't `*p` null if there are two null termini in the list? (i.e. the list looks like `-1, -1, ... some `func_ptr`s ... , 0, 0`) I thought the same; that's why I did the extra check with "if (*p)", as I mentioned in the other mail. However, in practice, __CTOR_END__ points to the first 0-terminator. Not sure why that is, but you can check with -Wl,-Map,map.txt. But yes, it's safer with that extra check added, then both iterations should be fine, regardless which one the symbol points to, in both ends. // Martin -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCHv2 1/4] crt: Add an implementation of __cxa_atexit and __cxa_thread_atexit
在 2018/8/2 19:22, Martin Storsjö 写道: > + > +typedef void (__thiscall * dtor)(void*); > +int __cxa_atexit(dtor dtor, void *obj, void *dso); > +int __cxa_thread_atexit(dtor dtor, void *obj, void *dso); > + > +typedef struct dtor_obj dtor_obj; > +struct dtor_obj { > + dtor dtor; It is a bit strange to see the same identifier be repeated here. I suggest you rename the typedef to `dtor_fn` or `dtor_proc`. These 4 patches look good to me. -- Best regards, LH_Mouse -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH] crt: Unify and simplify handling of constructor/destructor lists
在 2018/8/2 19:02, Martin Storsjö 写道: > -#ifdef __clang__ > extern func_ptr __CTOR_END__[]; > extern func_ptr __DTOR_END__[]; > > void __do_global_ctors (void) > { > static func_ptr *p = __CTOR_END__ - 1; > + // If the linker provided its own __CTOR_LIST__ in addition to the one > + // we provide, we'd actually stop at __CTOR_LIST__+1, but that's no problem > + // for this function. > while (*p != (func_ptr) -1) { > (*(p))(); At the very firsts iteration, isn't `*p` null if there are two null termini in the list? (i.e. the list looks like `-1, -1, ... some `func_ptr`s ... , 0, 0`) > p--; > @@ -42,30 +48,6 @@ void __do_global_ctors (void) > atexit (__do_global_dtors); > } > -- Best regards, LH_Mouse -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH] crt: Unify and simplify handling of constructor/destructor lists
On Thu, 2 Aug 2018, Liu Hao wrote: 在 2018-08-02 19:02, Martin Storsjö 写道: Signed-off-by: Martin Storsjö --- mingw-w64-crt/crt/crtdll.c | 2 -- mingw-w64-crt/crt/crtexe.c | 2 -- mingw-w64-crt/crt/gccmain.c | 34 -- 3 files changed, 8 insertions(+), 30 deletions(-) diff --git a/mingw-w64-crt/crt/crtdll.c b/mingw-w64-crt/crt/crtdll.c index 50a9eb4..af69573 100644 --- a/mingw-w64-crt/crt/crtdll.c +++ b/mingw-w64-crt/crt/crtdll.c @@ -40,12 +40,10 @@ extern _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[]; extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[]; extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[]; -#ifdef __clang__ __attribute__ (( __section__ (".ctors"), __used__ , aligned(sizeof(void * const void * __CTOR_LIST__ = (void *) -1; __attribute__ (( __section__ (".dtors"), __used__ , aligned(sizeof(void * const void * __DTOR_LIST__ = (void *) -1; __attribute__ (( __section__ (".ctors.9"), __used__ , aligned(sizeof(void * const void * __CTOR_END__ = (void *) 0; __attribute__ (( __section__ (".dtors.9"), __used__ , aligned(sizeof(void * const void * __DTOR_END__ = (void *) 0; -#endif Does GNU LD recognize the `.9` suffix? The known and working way to sort sections for GNU LD for Windows is .ctors$ .ctors$foo .ctors$ and such sections are sorted in alphabet order rather than numeric order. This could explain why these symbols are not emitted for GCC. Yes, GNU LD supports it - you get similar things emitted by GCC if you specify a constructor priority. Case example: $ cat test.cpp void other(void); class Foo { public: Foo() { other(); } }; Foo foo1 __attribute__((init_priority(101))); Foo foo2 __attribute__((init_priority(65534))); $ x86_64-w64-mingw32-g++ -S test.cpp -o - -O2 | grep ctors .section.ctors.65434,"w" .section.ctors.1,"w" The number after .ctors is 65535 minus the value specified in init_priority. The values are padded to 5 digits with leading zeros, and GNU LD sorts them alphabetically when linking, which is equal to numeric order when it's zero padded. Since the values are in the range 0-65535, the sentinel at 9 will always be sorted last. diff --git a/mingw-w64-crt/crt/gccmain.c b/mingw-w64-crt/crt/gccmain.c index 54cbf02..44ff653 100644 --- a/mingw-w64-crt/crt/gccmain.c +++ b/mingw-w64-crt/crt/gccmain.c @@ -23,18 +23,24 @@ __do_global_dtors (void) while (*p) { - (*(p)) (); + // If the linker provided its own __DTOR_LIST__ in addition to the + // one we provide, we'd end up with the first pointer here being + // a (func_ptr)-1 sentinel. jon_y used to require all comments be C89-ish. I am not totally clear about the reason. May he elaborate a little. I can change them to that style if there's a preference for that - I'll not repost any new version of the patch just for that though. Just to be safe, I'm amending the patch locally like this as well: @@ -42,7 +42,8 @@ void __do_global_ctors (void) // we provide, we'd actually stop at __CTOR_LIST__+1, but that's no problem // for this function. while (*p != (func_ptr) -1) { -(*(p))(); +if (*p) + (*(p))(); p--; } That doesn't turn out to be necessary in my testing with GNU LD, but it's safer that way. // Martin -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
[Mingw-w64-public] [PATCH] crt: Unify and simplify handling of constructor/destructor lists
GNU binutils ld traditionally provides __CTOR_LIST__ and __DTOR_LIST__ symbols via a linker script, while lld doesn't. Due to this, we previously provided our own copy of these symbols while building with clang (assuming that means we'd be linking with lld), see 1e81200e88f. In an attempt to unify things, binutils 2.30 changed the linker script to conditionally provide these symbols, in case they were undefined, but otherwise prefer the ones provided by object files linked in. This attempt failed though (and was reverted for binutils 2.31), since libgcc turned out to contain dummy fallback symbols named __CTOR_LIST__ and __DTOR_LIST__, without any section assignments, meaning they weren't actually sorted by the linker along with any of the constructors to be called. In order to unify and simplify things, always provide our own version of these symbols. When using a binutils version other than 2.30, that always unconditionally provides its own __CTOR_LIST__/__DTOR_LIST__ symbols, this doesn't result in a conflict with multiply defined symbols, but ld just silently uses the symbol it provided via the linker script, but retains the data provided from the object files. (Tested with binutils 2.22, 2.26 and 2.30.) In such a case, the list between __CTOR_LIST__ and __CTOR_END__ will contain one extra (func_ptr)-1 entry at the start, the one provided by code (and one extra, for our purposes harmless, null terminator at the end). By always providing our own, and adapting the code for iterating the lists to cope with a stray extra sentinel in the list, we can use the same logic for all cases of both binutils ld and lld, including the previously broken binutils 2.30. Signed-off-by: Martin Storsjö --- mingw-w64-crt/crt/crtdll.c | 2 -- mingw-w64-crt/crt/crtexe.c | 2 -- mingw-w64-crt/crt/gccmain.c | 34 -- 3 files changed, 8 insertions(+), 30 deletions(-) diff --git a/mingw-w64-crt/crt/crtdll.c b/mingw-w64-crt/crt/crtdll.c index 50a9eb4..af69573 100644 --- a/mingw-w64-crt/crt/crtdll.c +++ b/mingw-w64-crt/crt/crtdll.c @@ -40,12 +40,10 @@ extern _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[]; extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[]; extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[]; -#ifdef __clang__ __attribute__ (( __section__ (".ctors"), __used__ , aligned(sizeof(void * const void * __CTOR_LIST__ = (void *) -1; __attribute__ (( __section__ (".dtors"), __used__ , aligned(sizeof(void * const void * __DTOR_LIST__ = (void *) -1; __attribute__ (( __section__ (".ctors.9"), __used__ , aligned(sizeof(void * const void * __CTOR_END__ = (void *) 0; __attribute__ (( __section__ (".dtors.9"), __used__ , aligned(sizeof(void * const void * __DTOR_END__ = (void *) 0; -#endif /* TLS initialization hook. */ extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback; diff --git a/mingw-w64-crt/crt/crtexe.c b/mingw-w64-crt/crt/crtexe.c index e390074..5dcfefd 100644 --- a/mingw-w64-crt/crt/crtexe.c +++ b/mingw-w64-crt/crt/crtexe.c @@ -60,12 +60,10 @@ extern _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[]; extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[]; extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[]; -#ifdef __clang__ __attribute__ (( __section__ (".ctors"), __used__ , aligned(sizeof(void * const void * __CTOR_LIST__ = (void *) -1; __attribute__ (( __section__ (".dtors"), __used__ , aligned(sizeof(void * const void * __DTOR_LIST__ = (void *) -1; __attribute__ (( __section__ (".ctors.9"), __used__ , aligned(sizeof(void * const void * __CTOR_END__ = (void *) 0; __attribute__ (( __section__ (".dtors.9"), __used__ , aligned(sizeof(void * const void * __DTOR_END__ = (void *) 0; -#endif /* TLS initialization hook. */ extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback; diff --git a/mingw-w64-crt/crt/gccmain.c b/mingw-w64-crt/crt/gccmain.c index 54cbf02..44ff653 100644 --- a/mingw-w64-crt/crt/gccmain.c +++ b/mingw-w64-crt/crt/gccmain.c @@ -23,18 +23,24 @@ __do_global_dtors (void) while (*p) { - (*(p)) (); + // If the linker provided its own __DTOR_LIST__ in addition to the + // one we provide, we'd end up with the first pointer here being + // a (func_ptr)-1 sentinel. + if (*p != (func_ptr) -1) +(*(p)) (); p++; } } -#ifdef __clang__ extern func_ptr __CTOR_END__[]; extern func_ptr __DTOR_END__[]; void __do_global_ctors (void) { static func_ptr *p = __CTOR_END__ - 1; + // If the linker provided its own __CTOR_LIST__ in addition to the one + // we provide, we'd actually stop at __CTOR_LIST__+1, but that's no problem + // for this function. while (*p != (func_ptr) -1) { (*(p))(); p--; @@ -42,30 +48,6 @@ void __do_global_ctors (void) atexit (__do_global_dtors); } -#else -// old method that iterates the list twice because old linker scripts do not have __CTOR_END__ - -void -__do_global_ctors (void) -{ - unsigned long nptrs = (unsigned long) (ptrdiff_t)
[Mingw-w64-public] [PATCHv2 1/4] crt: Add an implementation of __cxa_atexit and __cxa_thread_atexit
In order to properly call destructors of a DLL when that DLL is unloaded, we need to provide these as part of the static library libmingw32.a, which gets linked into the module itself. C++ libraries (both libstdc++ and libcxxabi) can also provide the function __cxa_thread_atexit, and defer the actual handling to the platform via a __cxa_thread_atexit_impl function. However, if linking a C++ standard library dynamically, that would mean that all destructors are registered in the C++ DLL and only invoked when that one is unloaded, not when an individual DLL gets unloaded. Therefore we need to provide these functions directly in a static library that gets linked into each module (if referenced). This probably doesn't end up used with GCC and libstdc++ (which still probably provides its own __cxa_thread_atexit which will be linked before libmingw32.a). But it does work with clang (if compiling with -fuse-cxa-atexit) and libcxxabi (which doesn't provide any __cxa_thread_atexit when targeting mingw). Signed-off-by: Martin Storsjö --- Removed code for cleaning up other threads' pending destructors, added a verbose comment about the matter. --- mingw-w64-crt/Makefile.am | 2 +- mingw-w64-crt/crt/cxa_atexit.c | 113 + 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 mingw-w64-crt/crt/cxa_atexit.c diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index 8ca1072..d98fa3a 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am @@ -119,7 +119,7 @@ src_libmingw32=include/oscalls.h include/internal.h include/sect_attribs.h \ crt/mingw_custom.c crt/mingw_helpers.c \ crt/pseudo-reloc.c crt/udll_argv.c \ crt/xtxtmode.c crt/crt_handler.c\ - crt/tlsthrd.c crt/tlsmthread.c crt/tlsmcrt.c + crt/tlsthrd.c crt/tlsmthread.c crt/tlsmcrt.c crt/cxa_atexit.c src_libscrnsave=libsrc/scrnsave.c src_libscrnsavw=libsrc/scrnsave.c diff --git a/mingw-w64-crt/crt/cxa_atexit.c b/mingw-w64-crt/crt/cxa_atexit.c new file mode 100644 index 000..d74968d --- /dev/null +++ b/mingw-w64-crt/crt/cxa_atexit.c @@ -0,0 +1,113 @@ +/** + * 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 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include + + +typedef void (__thiscall * dtor)(void*); +int __cxa_atexit(dtor dtor, void *obj, void *dso); +int __cxa_thread_atexit(dtor dtor, void *obj, void *dso); + +typedef struct dtor_obj dtor_obj; +struct dtor_obj { + dtor dtor; + void *obj; + dtor_obj *next; +}; + +HANDLE __dso_handle; + +static CRITICAL_SECTION lock; +static int inited = 0; +static dtor_obj *global_dtors = NULL; +static __thread dtor_obj *tls_dtors = NULL; + +int __cxa_atexit(dtor dtor, void *obj, void *dso) { + if (!inited) +return 1; + assert(!dso || dso == &__dso_handle); + dtor_obj *handler = (dtor_obj *) calloc(1, sizeof(*handler)); + if (!handler) +return 1; + handler->dtor = dtor; + handler->obj = obj; + EnterCriticalSection(); + handler->next = global_dtors; + global_dtors = handler; + LeaveCriticalSection(); + return 0; +} + +static void run_dtor_list(dtor_obj **ptr) { + dtor_obj *list = *ptr; + while (list) { +list->dtor(list->obj); +dtor_obj *next = list->next; +free(list); +list = next; + } + *ptr = NULL; +} + +int __cxa_thread_atexit(dtor dtor, void *obj, void *dso) { + if (!inited) +return 1; + assert(!dso || dso == &__dso_handle); + dtor_obj *handler = (dtor_obj *) calloc(1, sizeof(*handler)); + if (!handler) +return 1; + handler->dtor = dtor; + handler->obj = obj; + handler->next = tls_dtors; + tls_dtors = handler; + return 0; +} + +static void WINAPI tls_callback(HANDLE hDllHandle, DWORD dwReason, LPVOID __UNUSED_PARAM(lpReserved)) { + switch (dwReason) { + case DLL_PROCESS_ATTACH: +if (inited == 0) { + InitializeCriticalSection(); + __dso_handle = hDllHandle; +} +inited = 1; +break; + case DLL_PROCESS_DETACH: +// If there are other threads still running that haven't been detached, +// we don't attempt to run their destructors (MSVC doesn't either), but +// simply leak the destructor list and whatever resources the destructors +// would have released. +// From Vista onwards, we could have used FlsAlloc to get a TLS key that +// runs a destructor on each thread that has a value attached ot it, but +// since MSVC doesn't run destructors on other threads in this case, +// users shouldn't assume it and we don't attempt to do anything potentially +// risky about it. TL;DR, threads with pending TLS destructors for a DLL +// need to be joined before unloading the DLL. +run_dtor_list(_dtors); +run_dtor_list(_dtors); +
[Mingw-w64-public] [PATCHv2 4/4] crt: Use _register_thread_local_exe_atexit_callback for TLS dtors
The standard says that destructors of thread local objects should be invoked before any other destructors. Since the destructors are called by the CRT via what has been registered via atexit (ordered so that the function registered last will be executed first), we need to use this API from UCRT to request a function to be executed before any other atexit callback. Signed-off-by: Martin Storsjö --- mingw-w64-crt/crt/cxa_atexit.c | 12 1 file changed, 12 insertions(+) diff --git a/mingw-w64-crt/crt/cxa_atexit.c b/mingw-w64-crt/crt/cxa_atexit.c index d74968d..560e93e 100644 --- a/mingw-w64-crt/crt/cxa_atexit.c +++ b/mingw-w64-crt/crt/cxa_atexit.c @@ -14,6 +14,7 @@ #include #include #include +#include typedef void (__thiscall * dtor)(void*); @@ -28,6 +29,7 @@ struct dtor_obj { }; HANDLE __dso_handle; +extern char __mingw_module_is_dll; static CRITICAL_SECTION lock; static int inited = 0; @@ -81,6 +83,16 @@ static void WINAPI tls_callback(HANDLE hDllHandle, DWORD dwReason, LPVOID __UNUS if (inited == 0) { InitializeCriticalSection(); __dso_handle = hDllHandle; + // We can only call _register_thread_local_exe_atexit_callback once + // in a thread; if we call it a second time the process terminates. + // When DLLs are unloaded, this callback is invoked before we run the + // _onexit tables, but for exes, we need to ask this to be called before + // all other registered atexit functions. + // Since we are registered as a normal TLS callback, we will be called + // another time later as well, but that doesn't matter, it's safe to + // invoke this with DLL_PROCESS_DETACH twice. + if (!__mingw_module_is_dll) +_register_thread_local_exe_atexit_callback(tls_callback); } inited = 1; break; -- 2.7.4 -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
[Mingw-w64-public] [PATCHv2 3/4] crt: Expose a private variable that indicates whether the module is an exe or dll
Signed-off-by: Martin Storsjö --- mingw-w64-crt/crt/crtdll.c | 2 ++ mingw-w64-crt/crt/crtexe.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mingw-w64-crt/crt/crtdll.c b/mingw-w64-crt/crt/crtdll.c index 50a9eb4..5f53602 100644 --- a/mingw-w64-crt/crt/crtdll.c +++ b/mingw-w64-crt/crt/crtdll.c @@ -210,3 +210,5 @@ int __cdecl atexit (_PVFV func) { return _register_onexit_function(_table, (_onexit_t)func); } + +char __mingw_module_is_dll = 1; diff --git a/mingw-w64-crt/crt/crtexe.c b/mingw-w64-crt/crt/crtexe.c index 7000a19..3f724e5 100644 --- a/mingw-w64-crt/crt/crtexe.c +++ b/mingw-w64-crt/crt/crtexe.c @@ -430,3 +430,5 @@ int __cdecl atexit (_PVFV func) { return _onexit((_onexit_t)func) ? 0 : -1; } + +char __mingw_module_is_dll = 0; -- 2.7.4 -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
[Mingw-w64-public] [PATCHv2 2/4] crt: Declare _register_thread_local_exe_atexit_callback in headers, provide fallback
This function is available in the universal CRT. Add a best effort fallback version of it for other CRTs. Signed-off-by: Martin Storsjö --- mingw-w64-crt/Makefile.am| 1 + mingw-w64-crt/misc/register_tls_atexit.c | 29 + mingw-w64-headers/crt/process.h | 3 +++ 3 files changed, 33 insertions(+) create mode 100644 mingw-w64-crt/misc/register_tls_atexit.c diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index d98fa3a..3745a2f 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am @@ -157,6 +157,7 @@ src_libws2_32=libsrc/ws2_32.c \ src_msvcrt_common=\ misc/onexit_table.c \ + misc/register_tls_atexit.c \ stdio/acrt_iob_func.c src_msvcrt=\ diff --git a/mingw-w64-crt/misc/register_tls_atexit.c b/mingw-w64-crt/misc/register_tls_atexit.c new file mode 100644 index 000..338cffd --- /dev/null +++ b/mingw-w64-crt/misc/register_tls_atexit.c @@ -0,0 +1,29 @@ +/** + * 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 +#include +#include +#include + +static _tls_callback_type callback; + +static void run_callback(void) +{ + if (callback) +callback(NULL, DLL_PROCESS_DETACH, 0); + callback = NULL; +} + +int __cdecl _register_thread_local_exe_atexit_callback(_tls_callback_type cb) +{ + 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); +} + +typeof(_register_thread_local_exe_atexit_callback) *__MINGW_IMP_SYMBOL(_register_thread_local_exe_atexit_callback) = _register_thread_local_exe_atexit_callback; diff --git a/mingw-w64-headers/crt/process.h b/mingw-w64-headers/crt/process.h index b698685..5c38766 100644 --- a/mingw-w64-headers/crt/process.h +++ b/mingw-w64-headers/crt/process.h @@ -55,6 +55,9 @@ extern "C" { #endif /* _CRT_TERMINATE_DEFINED */ + typedef void (__stdcall *_tls_callback_type)(void*,unsigned long,void*); + _CRTIMP int __cdecl _register_thread_local_exe_atexit_callback(_tls_callback_type callback); + void __cdecl __MINGW_NOTHROW _cexit(void); void __cdecl __MINGW_NOTHROW _c_exit(void); _CRTIMP int __cdecl _getpid(void); -- 2.7.4 -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH 1/4] crt: Add an implementation of __cxa_atexit and __cxa_thread_atexit
在 2018-08-02 14:58, Martin Storsjö 写道: > Sorry for the double post, I accidentally dropped Liu from the CC of the > previous reply, > It doesn't matter, as I have subscribed to this list, and my client (ThunderBird) filters out duplicate mails. BTW, I have my name spelled in the surname-first order. People mistake my surname for given name so frequently, which I am quite accustomed to. :> -- Best regards, LH_Mouse -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH 1/4] crt: Add an implementation of __cxa_atexit and __cxa_thread_atexit
Sorry for the double post, I accidentally dropped Liu from the CC of the previous reply, On Thu, 2 Aug 2018, Martin Storsjö wrote: On Thu, 2 Aug 2018, Liu Hao wrote: 在 2018/8/2 13:56, Martin Storsjö 写道: Yes, a responsible user would join all his threads before calling exit() or returning from main, there's no disagreement about that. But the problematic case I'm thinking about is when you load and unload e.g. plugins, which may contain TLS objects. If more than one long running threads (which aren't stopped meanwhile) touch the plugin while it is loaded (with proper synchronization of course), you'll have leaks. // Martin I don't know how many people unload DLLs in practice. AFAIU once a DLL is loaded and a function from it is called, it is virtually impossible to eliminate the possibility of references of anything in that DLL, especially C++ RTTI, virtual functions, specialized function templates, etc. If people don't ever unload a DLL, thread local objects in that DLL will be considered reachable and therefore are not leaks. VLC is the specific example I have in mind, which regularly loads and unloads DLL plugins. On unload, nothing in the remaining process should have any handle to anything sourced from this DLL. The plugins themselves only expose a C API although they internally can use C++. VLC also has numerous threads running. I'm not sure if more than one thread actually will interact with each plugin though, and if that is the same as does the loading of the plugin, or if it might be a different one. ... which is the reason why I think this should be a reasonable behaviour. But as MSVC's implementation of this doesn't call TLS destructors for other threads, I guess it's fine to just document this as the intended behaviour, and have VLC reconsider their use of TLS objects here (either it's all actually done on the same thread that unloads the DLL, or threads that touched it are joined before unloading it, or they shouldn't use it). // Martin -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH 1/4] crt: Add an implementation of __cxa_atexit and __cxa_thread_atexit
On Thu, 2 Aug 2018, Martin Storsjö wrote: On Thu, 2 Aug 2018, Liu Hao wrote: 在 2018/8/2 13:56, Martin Storsjö 写道: Yes, a responsible user would join all his threads before calling exit() or returning from main, there's no disagreement about that. But the problematic case I'm thinking about is when you load and unload e.g. plugins, which may contain TLS objects. If more than one long running threads (which aren't stopped meanwhile) touch the plugin while it is loaded (with proper synchronization of course), you'll have leaks. // Martin I don't know how many people unload DLLs in practice. AFAIU once a DLL is loaded and a function from it is called, it is virtually impossible to eliminate the possibility of references of anything in that DLL, especially C++ RTTI, virtual functions, specialized function templates, etc. If people don't ever unload a DLL, thread local objects in that DLL will be considered reachable and therefore are not leaks. VLC is the specific example I have in mind, which regularly loads and unloads DLL plugins. On unload, nothing in the remaining process should have any handle to anything sourced from this DLL. The plugins themselves only expose a C API although they internally can use C++. VLC also has numerous threads running. I'm not sure if more than one thread actually will interact with each plugin though, and if that is the same as does the loading of the plugin, or if it might be a different one. ... which is the reason why I think this should be a reasonable behaviour. But as MSVC's implementation of this doesn't call TLS destructors for other threads, I guess it's fine to just document this as the intended behaviour, and have VLC reconsider their use of TLS objects here (either it's all actually done on the same thread that unloads the DLL, or threads that touched it are joined before unloading it, or they shouldn't use it). // Martin -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
Re: [Mingw-w64-public] [PATCH 1/4] crt: Add an implementation of __cxa_atexit and __cxa_thread_atexit
在 2018/8/2 13:56, Martin Storsjö 写道: > Yes, a responsible user would join all his threads before calling exit() > or returning from main, there's no disagreement about that. > > But the problematic case I'm thinking about is when you load and unload > e.g. plugins, which may contain TLS objects. If more than one long > running threads (which aren't stopped meanwhile) touch the plugin while > it is loaded (with proper synchronization of course), you'll have leaks. > > // Martin I don't know how many people unload DLLs in practice. AFAIU once a DLL is loaded and a function from it is called, it is virtually impossible to eliminate the possibility of references of anything in that DLL, especially C++ RTTI, virtual functions, specialized function templates, etc. If people don't ever unload a DLL, thread local objects in that DLL will be considered reachable and therefore are not leaks. -- Best regards, LH_Mouse -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public