Skip to content
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

Avoid sharing the parent process's stdin handle to python on Windows + other Windows bat script fixes #15146

Merged

Conversation

juj
Copy link
Collaborator

@juj juj commented Sep 27, 2021

This PR performs the following fixes:

  1. Add an env. var EM_WORKAROUND_PYTHON_BUG_34780 that enables avoiding sharing the parent process's stdin handle to python when invoking python via emcc.bat script, to prevent a rare python deadlock hang bug https://bugs.python.org/issue34780
  2. Add an env. var EM_WORKAROUND_WIN7_BAD_ERRORLEVEL_BUG that enables explicitly exiting the batch script with python errorlevel code, to work around a Windows 7 bad batch script exit code issue. We have not found a description of this bug on the web, but the issue that occurs is that on Windows 7, the invoked batch scripts return with a nonzero exit code, even if the python subprocess call was clean with exit code zero and the %ERRORLEVEL% variable in the batch script itself was zero. This is possibly caused by the same python bug 34780 as above, but we have no confirmation about this. Therefore it is important to treat this separately because the "nuclear option" of exit %ERRORLEVEL% will exit the parent shell as well.
  3. Fix batch scripts to not leak env. vars to parent shell by adding a setlocal directive.
  4. Fix a peculiar Windows batch script parsing issue where if a :: comment line is placed inside a if () block, it will be somehow parsed by the interpreter. E.g. if one would have a bat script
@if ""=="" (
:: If _EMCC_CCACHE is not defined below, do a regular invocation of em++.py compiler.
:: Python Windows bug https://bugs.python.org/issue34780: If emcc.bat was invoked via a
:: shared stdin handle from the parent process, and that parent process stdin handle is in
:: a certain state, running python.exe might hang here. To work around this, invoke python
:: with '< NUL' stdin to avoid sharing the parent's stdin handle to it, avoiding the hang.
  echo hello
)

then running this bat script will print

C:\code>test.bat
The system cannot find the drive specified.
The system cannot find the drive specified.
hello

These two error prints come from Windows bat script interpreter somehow parsing the comment strings as path names.

However, the following bat script

:: If _EMCC_CCACHE is not defined below, do a regular invocation of em++.py compiler.
:: Python Windows bug https://bugs.python.org/issue34780: If emcc.bat was invoked via a
:: shared stdin handle from the parent process, and that parent process stdin handle is in
:: a certain state, running python.exe might hang here. To work around this, invoke python
:: with '< NUL' stdin to avoid sharing the parent's stdin handle to it, avoiding the hang.
@if ""=="" (
  echo hello
)

correctly prints out

C:\code>test.bat
hello

so Windows parses comments somehow differently inside if () sections. This means that we should avoid placing :: comments inside if () sections in these batch scripts.

@juj juj added the windows label Sep 27, 2021
Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems necessary, but it does mean we can't do emcc.bat < file.cpp I assume? If so, documenting that at least might be a good idea.

@sbc100
Copy link
Collaborator

sbc100 commented Sep 27, 2021

This seems necessary, but it does mean we can't do emcc.bat < file.cpp I assume? If so, documenting that at least might be a good idea.

I thou would need to add - to make that work.. but yes it would be shame too loose that compatibility. Today I can do:

echo "int foo;" | gcc -x c -c -
echo "int foo;" | clang -x c -c -
echo "int foo;" | emcc -x c -c -

On the other hand as long as this only effects windows I think they usage of stdin is probably less there ..

@juj juj changed the title Avoid sharing the parent process's stdin handle to python on Windows. Avoid sharing the parent process's stdin handle to python on Windows + other Windows bat script fixes Oct 6, 2021
@juj juj force-pushed the avoid_sharing_parent_stdin_handle_windows branch from c718466 to 1d37c9e Compare October 6, 2021 07:56
…ng python via emcc.bat script, to prevent a rare python deadlock hang.
Work around a Windows 7 batch script exit code issue.
Work around a Windows Python spawn issue: https://bugs.python.org/issue34780
… statement (an if() statement would taint the 0 variable)
@juj juj force-pushed the avoid_sharing_parent_stdin_handle_windows branch from cad8916 to 28e26eb Compare October 6, 2021 08:07
@juj
Copy link
Collaborator Author

juj commented Oct 6, 2021

Updated this PR to contain all the different changes to the batch scripts altogether. Realizing that not everyone will be affected by the Python issue, I opted to gate these workarounds behind env. vars so that people who are not affected will not lose out on features.

@%CMD% %*
@exit %ERRORLEVEL%
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the /b does this not exit the entire cmd.exe shell?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, though unfortunately with the /b flag that will not fix the Windows 7 issue. The /b flag is used in the other part to avoid a goto, which would reset the %errorlevel% variable to zero.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So users of EM_WORKAROUND_WIN7_BAD_ERRORLEVEL_BUG are opting into not being able to use these tools in a command shell, is that the idea? Maybe it would never make sense there?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Sorry I should have read all of your above comments.. I see it mentions this there).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that is the case - when one enables EM_WORKAROUND_WIN7_BAD_ERRORLEVEL_BUG, that will cause the shell to quit. For command line uses that would be quite undesirable, hence placing it under a separate workaround env. var.

@juj juj enabled auto-merge (squash) October 6, 2021 15:07
@sbc100
Copy link
Collaborator

sbc100 commented Oct 6, 2021

I the old version of this script we don't call exit at all.. but somehow the exit code is still set correctly? (I guess because the emcc command is the very last one?).

I wonder if it possible for the ":NORMAL" case to continue to work that way.. if we place it last in the script can we avoid calling exit at all maybe?

:NORMAL
@%CMD% %*

That way maybe EM_WORKAROUND_WIN7_BAD_ERRORLEVEL_BUG will only be needed if EM_WORKAROUND_PYTHON_BUG_34780 is also used?

@sbc100
Copy link
Collaborator

sbc100 commented Oct 6, 2021

Also maybe we would not longer need NORMAL_EXIT at all in that case?

@juj
Copy link
Collaborator Author

juj commented Oct 6, 2021

I wonder if it possible for the ":NORMAL" case to continue to work that way.. if we place it last in the script can we avoid calling exit at all maybe?

That is a very good suggestion. Updated to that form.

Also maybe we would not longer need NORMAL_EXIT at all in that case?

We do need that case, if we want to orthogonally support all combinations of EM_WORKAROUND_WIN7_BAD_ERRORLEVEL_BUG and EM_WORKAROUND_PYTHON_BUG_34780. I don't think it is a too bad thing to have the whole matrix (probably more consistent to have so, rather than oddly omit one of them)

@juj
Copy link
Collaborator Author

juj commented Oct 6, 2021

I the old version of this script we don't call exit at all.. but somehow the exit code is still set correctly? (I guess because the emcc command is the very last one?).

Yes, normally %ERRORLEVEL% is received from the last command in the file. However on Windows 7 we observe that even if %ERRORLEVEL% is zero in the bat script right after a call to python emcc.py, the bat script still incorrectly exits with ERRORLEVEL=1. Explicitly quitting with exit %ERRORLEVEL% works around that.

@sbc100
Copy link
Collaborator

sbc100 commented Oct 6, 2021

I the old version of this script we don't call exit at all.. but somehow the exit code is still set correctly? (I guess because the emcc command is the very last one?).

Yes, normally %ERRORLEVEL% is received from the last command in the file. However on Windows 7 we observe that even if %ERRORLEVEL% is zero in the bat script right after a call to python emcc.py, the bat script still incorrectly exits with ERRORLEVEL=1. Explicitly quitting with exit %ERRORLEVEL% works around that.

Oh I see.. so that issue already exists today and is completely separate to the other one. Make sense.

@sbc100
Copy link
Collaborator

sbc100 commented Oct 6, 2021

I the old version of this script we don't call exit at all.. but somehow the exit code is still set correctly? (I guess because the emcc command is the very last one?).

Yes, normally %ERRORLEVEL% is received from the last command in the file. However on Windows 7 we observe that even if %ERRORLEVEL% is zero in the bat script right after a call to python emcc.py, the bat script still incorrectly exits with ERRORLEVEL=1. Explicitly quitting with exit %ERRORLEVEL% works around that.

Oh I see.. so that issue already exists today and is completely separate to the other one. Make sense.

Does that mean that emcc.bat on windows 7 always returns success today? If windows 7 is so badly broken (and has been like that forever) how are not hearing more about this?

@juj
Copy link
Collaborator Author

juj commented Oct 6, 2021

Does that mean that emcc.bat on windows 7 always returns success today?

No. We are seeing on Windows 7 when we spawn emcc.bat via tundra.exe, it will cause emcc.bat to always return exit code 1 (failed) back to tundra subprocess exit code. When emcc.bat is launched from cmdline as usual on Win 7, it does return 0 as usual. On Win8 and newer, this does not occur.

@juj juj merged commit 75b0a5f into emscripten-core:main Oct 6, 2021
juj added a commit to Unity-Technologies/emscripten that referenced this pull request Oct 11, 2021
radical added a commit to radical/runtime that referenced this pull request Jun 7, 2022
Issue - emscripten-core/emscripten#15146

Emscripten added a workaround enabled by setting
the environment variable - `EM_WORKAROUND_PYTHON_BUG_34780`.
radical added a commit to dotnet/runtime that referenced this pull request Jun 7, 2022
* [wasm] Workaround a python bug which can cause em* scripts to hang

Issue - emscripten-core/emscripten#15146

Emscripten added a workaround enabled by setting
the environment variable - `EM_WORKAROUND_PYTHON_BUG_34780`.

* [wasm] Wasm.Build.Tests - use a local copy of `dotnet`

.. to avoid conflicting with other instances on helix.

* don't log output from robocopy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants