Fix data race in wxGetTimeZone()

We could return a wrong value from this function if two threads called
it simultaneously, as gmtoffset value could be returned without DST
adjustment in one of them. And just accessing it from two different
threads without synchronization was a data race on its own.

Fix both problems by using an atomic int for it and taking care to only
set it to the correct value.
This commit is contained in:
Vadim Zeitlin 2023-03-12 18:54:26 +01:00
parent dd8935b07d
commit b3ff1f3e61

View file

@ -37,6 +37,10 @@
#endif
#endif
#ifdef WX_GMTOFF_IN_TM
#include <atomic>
#endif
#include <time.h>
wxDECL_FOR_STRICT_MINGW32(void, tzset, (void));
@ -119,12 +123,10 @@ struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp)
int wxGetTimeZone()
{
#ifdef WX_GMTOFF_IN_TM
// set to true when the timezone is set
static bool s_timezoneSet = false;
static long gmtoffset = LONG_MAX; // invalid timezone
static std::atomic<int> s_gmtoffset{INT_MAX}; // invalid timezone
// ensure that the timezone variable is set by calling wxLocaltime_r
if ( !s_timezoneSet )
if ( s_gmtoffset == INT_MAX )
{
// just call wxLocaltime_r() instead of figuring out whether this
// system supports tzset(), _tzset() or something else
@ -132,20 +134,21 @@ int wxGetTimeZone()
struct tm tm;
wxLocaltime_r(&t, &tm);
s_timezoneSet = true;
// note that GMT offset is the opposite of time zone and so to return
// consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM
// cases we have to negate it
gmtoffset = -tm.tm_gmtoff;
int gmtoffset = static_cast<int>(-tm.tm_gmtoff);
// this function is supposed to return the same value whether DST is
// enabled or not, so we need to use an additional offset if DST is on
// as tm_gmtoff already does include it
if ( tm.tm_isdst )
gmtoffset += 3600;
s_gmtoffset = gmtoffset;
}
return (int)gmtoffset;
return s_gmtoffset;
#elif defined(__WINE__)
struct timeb tb;
ftime(&tb);