Skip to content

Commit 175a13e

Browse files
committed
fix: add unittest for it
Signed-off-by: yihong0618 <[email protected]>
1 parent ff3c7f4 commit 175a13e

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

Lib/test/test_repl.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,71 @@ def test_no_memory(self):
9898
# Exit code 120: Py_FinalizeEx() failed to flush stdout and stderr.
9999
self.assertIn(p.returncode, (1, 120))
100100

101+
@cpython_only
102+
def test_issue134163_exec_hang(self):
103+
# Complete reproduction code that simulates REPL exec() behavior
104+
# note these prints are used can not drop
105+
user_input = dedent("""
106+
exec('''
107+
def test_repl_hanging():
108+
print("=" * 60)
109+
print("Reproducing gh-134163 outside REPL")
110+
print("Simulating interactive interpreter exec() behavior")
111+
print("=" * 60)
112+
print()
113+
114+
# First, import and set up the memory failure condition
115+
print("Step 1: Setting up memory allocation failure...")
116+
print("Step 2: Preparing code that will trigger exception handling...")
117+
# Create a code object that will cause exception handling
118+
# This simulates what happens when REPL executes user input
119+
test_code = \"\"\"
120+
# This code will trigger the problematic code path
121+
# by causing an exception during execution when memory is constrained
122+
import _testcapi
123+
_testcapi.set_nomemory(0) # This line triggers the hang condition
124+
\"\"\"
125+
print("Step 3: Compiling test code...")
126+
try:
127+
compiled_code = compile(test_code, "<reproduce_script>", "exec")
128+
except Exception as e:
129+
print(f"Compilation failed: {e}")
130+
exit(1)
131+
print("Step 4: Executing code that triggers the hang condition...")
132+
print("BEFORE FIX: This would hang indefinitely")
133+
print("AFTER FIX: This should exit gracefully")
134+
print()
135+
try:
136+
exec(compiled_code, {"__name__": "__console__"})
137+
print("Code executed successfully (unexpected)")
138+
except SystemExit:
139+
print("SystemExit caught - re-raising")
140+
raise
141+
except Exception as e:
142+
print(f"Exception caught during exec(): {type(e).__name__}: {e}")
143+
print("This is the expected path - exception handling should work normally")
144+
# The showtraceback() equivalent would be called here in real REPL
145+
import traceback
146+
traceback.print_exc()
147+
148+
test_repl_hanging()
149+
''')
150+
""")
151+
p = spawn_repl()
152+
with SuppressCrashReport():
153+
p.stdin.write(user_input)
154+
output = kill_python(p)
155+
# The test should complete without hanging and show expected output
156+
# We expect either successful completion or controlled failure
157+
self.assertIn(p.returncode, (0, 1, 120))
158+
# Verify that the simulation steps were executed or that we got the expected memory error output
159+
# The key test is that it doesn't hang - if we get output, the test passed
160+
# Look for either the expected reproduction output or memory error indicators
161+
has_reproduction_output = "Reproducing gh-134163 outside REPL" in output
162+
has_memory_error_output = "object type name: MemoryError" in output
163+
self.assertTrue(has_reproduction_output or has_memory_error_output,
164+
f"Expected either reproduction output or memory error output, got: {output[:500]}...")
165+
101166
@cpython_only
102167
def test_multiline_string_parsing(self):
103168
# bpo-39209: Multiline string tokens need to be handled in the tokenizer

0 commit comments

Comments
 (0)