@@ -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