Skip to content

Commit a5f748c

Browse files
committed
gh-150436: Skip subprocess test on STATUS_DLL_INIT_FAILED (#150704)
If a subprocess spawned with CREATE_NEW_CONSOLE creation flag fails with STATUS_DLL_INIT_FAILED return code, skip the test. It's likely a memory allocation failure in the desktop heap memory which caused the DLL init failure. (cherry picked from commit e8034dd)
1 parent a2f00d4 commit a5f748c

4 files changed

Lines changed: 31 additions & 5 deletions

File tree

Lib/test/support/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3227,3 +3227,18 @@ def control_characters_c0() -> list[str]:
32273227
C0 control characters defined as the byte range 0x00-0x1F, and 0x7F.
32283228
"""
32293229
return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"]
3230+
3231+
3232+
STATUS_DLL_INIT_FAILED = 0xC0000142
3233+
def skip_on_low_desktop_heap_memory_subprocess(returncode):
3234+
if sys.platform not in ('win32', 'cygwin'):
3235+
return
3236+
# On Windows, STATUS_DLL_INIT_FAILED is a generic error code that could
3237+
# come from any of the DLLs being loaded when a new Python process is
3238+
# created. In practice, it's likely a memory allocation failure in the
3239+
# desktop heap memory which caused the DLL init failure, especially on
3240+
# process created with CREATE_NEW_CONSOLE creation flag. See the article:
3241+
# https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/desktop-heap-limitation-out-of-memory
3242+
if returncode == STATUS_DLL_INIT_FAILED:
3243+
raise unittest.SkipTest('gh-150436: DLL init failed, likely because '
3244+
'of low desktop heap memory')

Lib/test/test_cmd_line.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,7 @@ def test_python_legacy_windows_stdio(self):
996996
p = subprocess.run([sys.executable, "-c", code],
997997
creationflags=subprocess.CREATE_NEW_CONSOLE,
998998
env=env)
999+
support.skip_on_low_desktop_heap_memory_subprocess(p.returncode)
9991000
self.assertEqual(p.returncode, 0)
10001001

10011002
# Then test that FIleIO is used when PYTHONLEGACYWINDOWSSTDIO is set.
@@ -1004,6 +1005,7 @@ def test_python_legacy_windows_stdio(self):
10041005
p = subprocess.run([sys.executable, "-c", code],
10051006
creationflags=subprocess.CREATE_NEW_CONSOLE,
10061007
env=env)
1008+
support.skip_on_low_desktop_heap_memory_subprocess(p.returncode)
10071009
self.assertEqual(p.returncode, 0)
10081010

10091011
@unittest.skipIf("-fsanitize" in sysconfig.get_config_vars().get('PY_CFLAGS', ()),

Lib/test/test_msvcrt.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import unittest
55
from textwrap import dedent
66

7+
from test import support
78
from test.support import os_helper, requires_resource
89
from test.support.os_helper import TESTFN, TESTFN_ASCII
910

@@ -67,8 +68,12 @@ def run_in_separated_process(self, code):
6768
# Run test in a separated process to avoid stdin conflicts.
6869
# See: gh-110147
6970
cmd = [sys.executable, '-c', code]
70-
subprocess.run(cmd, check=True, capture_output=True,
71-
creationflags=subprocess.CREATE_NEW_CONSOLE)
71+
try:
72+
subprocess.run(cmd, check=True, capture_output=True,
73+
creationflags=subprocess.CREATE_NEW_CONSOLE)
74+
except subprocess.CalledProcessError as exc:
75+
support.skip_on_low_desktop_heap_memory_subprocess(exc.returncode)
76+
raise
7277

7378
def test_kbhit(self):
7479
code = dedent('''

Lib/test/test_subprocess.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3730,13 +3730,17 @@ def test_startupinfo_copy(self):
37303730
self.assertEqual(startupinfo.wShowWindow, subprocess.SW_HIDE)
37313731
self.assertEqual(startupinfo.lpAttributeList, {"handle_list": []})
37323732

3733+
# CREATE_NEW_CONSOLE creates a "popup" window.
3734+
@support.requires_resource('gui')
37333735
def test_creationflags(self):
37343736
# creationflags argument
37353737
CREATE_NEW_CONSOLE = 16
37363738
sys.stderr.write(" a DOS box should flash briefly ...\n")
3737-
subprocess.call(sys.executable +
3738-
' -c "import time; time.sleep(0.25)"',
3739-
creationflags=CREATE_NEW_CONSOLE)
3739+
rc = subprocess.call(sys.executable +
3740+
' -c "import time; time.sleep(0.25)"',
3741+
creationflags=CREATE_NEW_CONSOLE)
3742+
support.skip_on_low_desktop_heap_memory_subprocess(rc)
3743+
self.assertEqual(rc, 0)
37403744

37413745
def test_invalid_args(self):
37423746
# invalid arguments should raise ValueError

0 commit comments

Comments
 (0)