-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
std: prevent CreateProcess()
race on Windows
#20650
Conversation
Believe or not, `CreateProcess()` is racy if several threads create child processes: [0], [1], [2]. This caused some tests show crash dialogs during `make check-stage#-rpass`. More explanation: On Windows, `SetErrorMode()` controls display of error dialogs: it accepts new error mode and returns old error mode. The error mode is process-global and automatically inherited to child process when created. MSYS2 bash shell internally sets it to not show error dialogs, therefore `make check-stage#-rpass` should not show them either. However, [1] says that `CreateProcess()` internally invokes `SetErrorMode()` twice: at first it sets mode `0x8001` and saves original mode, and at second it restores original mode. So if two threads simultaneously call `CreateProcess()`, the first thread sets error mode to `0x8001` then the second thread recognizes that current error mode is `0x8001`. Therefore, The second thread will create process with wrong error mode. This really occurs inside `compiletest`: it creates several processes on each thread, so some `run-pass` tests are invoked with wrong error mode therefore show crash dialog. This commit adds `StaticMutex` for `CreateProcess()` call. This seems to fix the "dialog annoyance" issue. [0]: http://support.microsoft.com/kb/315939 [1]: https://code.google.com/p/nativeclient/issues/detail?id=2968 [2]: https://ghc.haskell.org/trac/ghc/ticket/2650
r? @huonw (rust_highfive has picked a reviewer for you, use r? to override) |
This is why we can't have nice things :( |
Regardless, impressive investigation! Thanks so much for finding this! |
Believe or not, `CreateProcess()` is racy if several threads create child processes: [0], [1], [2]. This caused some tests show crash dialogs during `make check-stage#-rpass`. More explanation: On Windows, `SetErrorMode()` controls display of error dialogs: it accepts new error mode and returns old error mode. The error mode is process-global and automatically inherited to child process when created. MSYS2 bash shell internally sets it to not show error dialogs, therefore `make check-stage#-rpass` should not show them either. However, [1] says that `CreateProcess()` internally invokes `SetErrorMode()` twice: at first it sets mode `0x8001` and saves original mode, and at second it restores original mode. So if two threads simultaneously call `CreateProcess()`, the first thread sets error mode to `0x8001` then the second thread recognizes that current error mode is `0x8001`. Therefore, The second thread will create process with wrong error mode. This really occurs inside `compiletest`: it creates several processes on each thread, so some `run-pass` tests are invoked with wrong error mode therefore show crash dialog. This commit adds `StaticMutex` for `CreateProcess()` call. This seems to fix the "dialog annoyance" issue. [0]: http://support.microsoft.com/kb/315939 [1]: https://code.google.com/p/nativeclient/issues/detail?id=2968 [2]: https://ghc.haskell.org/trac/ghc/ticket/2650
Hmm, I realized this may not be an ideal way in the long term. This patch addresses two issues:
For the first issue, lock has a drawback: non-Rust code still call For the second issue, it seems impossible to protect error mode without locking. However, @HNO3 found that Actually our goal is not to preserve error mode but just to avoid crash dialogs. We just may add Mutex at |
(Stack trace of each
I think there are many similar problems related to using process error mode in multi-threaded environment. Well, there's a brand new function |
Believe or not,
CreateProcess()
is racy if several threads createchild processes: 0, 1, 2.
This caused some tests show crash dialogs during
make check-stage#-rpass
.More explanation:
On Windows,
SetErrorMode()
controls display of error dialogs: itaccepts new error mode and returns old error mode.
The error mode is process-global and automatically inherited to child
process when created.
MSYS2 bash shell internally sets it to not show error dialogs, therefore
make check-stage#-rpass
should not show them either.However, 1 says that
CreateProcess()
internally invokesSetErrorMode()
twice: at first it sets mode0x8001
and savesoriginal mode, and at second it restores original mode.
So if two threads simultaneously call
CreateProcess()
, the firstthread sets error mode to
0x8001
then the second thread recognizesthat current error mode is
0x8001
. Therefore, The second thread willcreate process with wrong error mode.
This really occurs inside
compiletest
: it creates several processes oneach thread, so some
run-pass
tests are invoked with wrong error modetherefore show crash dialog.
This commit adds
StaticMutex
forCreateProcess()
call. This seemsto fix the "dialog annoyance" issue.