http://bugs.winehq.org/show_bug.cgi?id=58082
Bug ID: 58082 Summary: race condition in GlobalMemoryStatusEx() implementation Product: Wine Version: unspecified Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: kernel32 Assignee: wine-bugs@winehq.org Reporter: winehq@rastos.org Distribution: ---
I suspect that there is a race condition implementation of Win32 API function GlobalMemoryStatusEx().
This function has a local static variable cached_status of type MEMORYSTATUSEX. The content of this structure is returned by GlobalMemoryStatusEx() if tick count since last call is less then 1000.
https://gitlab.winehq.org/wine/wine/-/blob/6b04bdf25796c9c76815588bf7bdc36ff...
However when there are multiple threads calling GlobalMemoryStatusEx() at nearly the same time, then it can happen that:
1) Thread 1 checks (NtGetTickCount() - last_check) < 1000 and finds that it is false (e.g. because long time elapsed since system start and last_check is 0 because it is static). It sets last_check = NtGetTickCount() and proceeds with retrieving the information.
2) Thread 2 checks (NtGetTickCount() - last_check) < 1000 and finds that it is true because last_check was set by Thread 1 just a few ticks ago. And returns content of cached_status which is not yet filled.
3) Thread 1 proceeds with filling the structure retrieved via parameter and after filling it in, it saves it into cached_status.
The Thread 2 received content of cached_status that not yet populated with real information.
As a solution I suggest to move last_check = NtGetTickCount(); after cached_status = *status; assignment which means that (NtGetTickCount() - last_check) < 1000 condition will be satisfied only after cached_status is actually filled in.