mirror of
https://github.com/boostorg/nowide.git
synced 2026-07-21 13:23:48 +00:00
Workaround crash on exit for MinGW 32bit
There is a bug in GCC for 32bit MinGW until version 11. This causes a use-after free for destruction of `thread_local` variables that crash the application when the destructor accesses any member. In the tests it shows up as exit code/status `-1073741819` i.e. `0xC0000005`. Workaround this by not destructing the `stackstring` instance used to hold the value of the last `getenv` result. In the case where any call to `getenv` of a thread yielded a large value heap memory will be allocated and not freed due to this missing destructor call causing a memory leak, possibly for each thread. However values up to some length are stored on stack memory and hence the missing destructor call does not cause a memory leak as the type is essentially trivial in this state. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83562 Fixed by https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=7fc0f78c3f43af1967cb7b1ee8f4947f3b890aa2
This commit is contained in:
+37
-2
@@ -48,11 +48,46 @@ namespace nowide {
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
|
||||
namespace {
|
||||
// thread_local was broken on MinGW for all 32bit compiler releases prior to 11.x, see
|
||||
// https://sourceforge.net/p/mingw-w64/bugs/527/
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83562
|
||||
// Using a non-trivial destructor causes program termination on thread exit.
|
||||
#if defined(__MINGW32__) && !defined(__MINGW64__) && !defined(__clang__) && (__GNUC__ < 11)
|
||||
class stackstring_for_thread
|
||||
{
|
||||
union
|
||||
{
|
||||
boost::nowide::stackstring s_;
|
||||
};
|
||||
|
||||
public:
|
||||
stackstring_for_thread() : s_(){};
|
||||
// Empty destructor so the union member (using a non-trivial destructor) does not get destroyed.
|
||||
// This will leak memory if any is allocated by the stackstring for each terminated thread
|
||||
// but as most values fit into the stack buffer this is rare and still better than a crash.
|
||||
~stackstring_for_thread(){};
|
||||
void convert(const wchar_t* begin, const wchar_t* end)
|
||||
{
|
||||
s_.convert(begin, end);
|
||||
}
|
||||
|
||||
char* get()
|
||||
{
|
||||
return s_.get();
|
||||
}
|
||||
};
|
||||
#else
|
||||
using stackstring_for_thread = boost::nowide::stackstring;
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
char* getenv(const char* key)
|
||||
{
|
||||
thread_local stackstring value;
|
||||
thread_local stackstring_for_thread value;
|
||||
|
||||
const wshort_stackstring name(key);
|
||||
|
||||
@@ -72,7 +107,7 @@ namespace nowide {
|
||||
return 0;
|
||||
ptr = &tmp[0];
|
||||
}
|
||||
value.convert(ptr);
|
||||
value.convert(ptr, ptr + n);
|
||||
return value.get();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user