@@ -47,6 +47,9 @@ def _fixture():
4747print("rows:", len(df))
4848"""
4949
50+ #: What a child that started the harness prints first.
51+ _STARTED = gc ._STARTED_MARKER + "\n "
52+
5053
5154def test_wellformed_code_passes_all_stages ():
5255 result = verify_generated_code (GOOD , _fixture ())
@@ -90,14 +93,16 @@ def test_runtime_poison_blocks_banned_module_even_if_statically_allowed(monkeypa
9093 gc , "ALLOWED_IMPORTS" , frozenset ({* gc .ALLOWED_IMPORTS , "socket" })
9194 )
9295 result = verify_generated_code ("import socket\n " , _fixture ())
96+ assert result .infrastructure_failure is None , result .failures
9397 assert not result .passed
94- assert any ("exited" in f for f in result .failures )
98+ assert any ("generated code exited" in f for f in result .failures )
9599
96100
97101def test_timeout_is_enforced ():
98102 result = verify_generated_code (
99103 "while True:\n pass\n " , _fixture (), timeout = 3.0
100104 )
105+ assert result .infrastructure_failure is None , result .failures
101106 assert not result .passed
102107 assert any ("timeout" in f for f in result .failures )
103108
@@ -116,6 +121,7 @@ def test_pii_canary_in_stdout_is_reported():
116121 'print(df["memo"].tolist())\n '
117122 )
118123 result = verify_generated_code (code , _fixture ())
124+ assert result .infrastructure_failure is None , result .failures
119125 assert not result .passed
120126 assert any ("stdout leaked canary" in f for f in result .failures )
121127 assert "example.invalid" not in result .stdout # evidence itself is redacted
@@ -128,6 +134,7 @@ def test_input_file_overwrite_is_reported():
128134 'df.head(1).to_csv("your_data.csv", index=False)\n '
129135 )
130136 result = verify_generated_code (code , _fixture ())
137+ assert result .infrastructure_failure is None , result .failures
131138 assert not result .passed
132139 assert any ("modified its input file" in f for f in result .failures )
133140
@@ -145,6 +152,7 @@ def test_sandbox_pins_native_threads_and_enables_faulthandler(tmp_path):
145152 python = _fake_interpreter (
146153 tmp_path ,
147154 "import json, os, sys\n "
155+ f"print({ gc ._STARTED_MARKER !r} )\n "
148156 "print(json.dumps({'argv': sys.argv[1:], 'env': dict(os.environ)}))\n " ,
149157 )
150158 result = verify_generated_code (GOOD , _fixture (), python = python )
@@ -212,7 +220,7 @@ def test_ordinary_failure_keeps_traceback_tail(monkeypatch):
212220 stderr = "noise\n " * 300 + "ValueError: bad column\n "
213221
214222 def failed_child (args , ** kwargs ):
215- return subprocess .CompletedProcess (args , 1 , "" , stderr )
223+ return subprocess .CompletedProcess (args , 1 , _STARTED , stderr )
216224
217225 monkeypatch .setattr (gc .subprocess , "run" , failed_child )
218226 result = verify_generated_code (GOOD , _fixture ())
@@ -234,7 +242,7 @@ def _scripted_children(monkeypatch, outcomes):
234242 def child (args , ** kwargs ):
235243 code , stderr = outcomes [min (len (calls ), len (outcomes ) - 1 )]
236244 calls .append (code )
237- return subprocess .CompletedProcess (args , code , "" , stderr )
245+ return subprocess .CompletedProcess (args , code , _STARTED , stderr )
238246
239247 monkeypatch .setattr (gc .subprocess , "run" , child )
240248 return calls
@@ -265,3 +273,117 @@ def test_ordinary_failure_is_not_retried(monkeypatch):
265273 assert calls == [1 ]
266274 assert not result .passed
267275 assert result .native_crashes == ()
276+
277+
278+ _POSIX_ENV_KEYS = {
279+ "PYTHONDONTWRITEBYTECODE" ,
280+ "PYTHONNOUSERSITE" ,
281+ "FRESHDATA_NO_NETWORK" ,
282+ "HOME" ,
283+ "TMPDIR" ,
284+ "OMP_NUM_THREADS" ,
285+ "OPENBLAS_NUM_THREADS" ,
286+ "MKL_NUM_THREADS" ,
287+ "POLARS_MAX_THREADS" ,
288+ "RAYON_NUM_THREADS" ,
289+ "LANG" ,
290+ }
291+ _HOST_ENV = {"SYSTEMROOT" : r"C:\Windows" , "PATH" : r"C:\bin" , "USERPROFILE" : r"C:\u" }
292+
293+
294+ @pytest .mark .parametrize ("key" , ["SYSTEMROOT" , "SystemRoot" ])
295+ def test_sandbox_env_keeps_system_root_on_windows (tmp_path , key ):
296+ # CPython <= 3.10 on Windows cannot seed hash randomization without it.
297+ host = {key : r"C:\Windows" , "PATH" : r"C:\bin" , "USERPROFILE" : r"C:\u" }
298+ env = gc ._sandbox_env (tmp_path , os_name = "nt" , environ = host )
299+ assert env ["SystemRoot" ] == r"C:\Windows"
300+ assert set (env ) == _POSIX_ENV_KEYS | {"SystemRoot" }
301+
302+
303+ def test_sandbox_env_on_posix_is_unchanged (tmp_path ):
304+ env = gc ._sandbox_env (tmp_path , os_name = "posix" , environ = _HOST_ENV )
305+ assert env == {
306+ "PYTHONDONTWRITEBYTECODE" : "1" ,
307+ "PYTHONNOUSERSITE" : "1" ,
308+ "FRESHDATA_NO_NETWORK" : "1" ,
309+ "HOME" : str (tmp_path ),
310+ "TMPDIR" : str (tmp_path ),
311+ "OMP_NUM_THREADS" : "1" ,
312+ "OPENBLAS_NUM_THREADS" : "1" ,
313+ "MKL_NUM_THREADS" : "1" ,
314+ "POLARS_MAX_THREADS" : "1" ,
315+ "RAYON_NUM_THREADS" : "1" ,
316+ "LANG" : "C.UTF-8" ,
317+ }
318+
319+
320+ def test_windows_child_receives_system_root (monkeypatch ):
321+ class _WindowsOs :
322+ name = "nt"
323+ environ = _HOST_ENV
324+
325+ seen = {}
326+
327+ def child (args , ** kwargs ):
328+ seen .update (kwargs ["env" ])
329+ return subprocess .CompletedProcess (args , 0 , _STARTED + "rows: 2\n " , "" )
330+
331+ monkeypatch .setattr (gc , "os" , _WindowsOs )
332+ monkeypatch .setattr (gc .subprocess , "run" , child )
333+ result = verify_generated_code (GOOD , _fixture ())
334+ assert result .passed , result .failures
335+ assert seen ["SystemRoot" ] == r"C:\Windows"
336+ assert "PATH" not in seen
337+ assert result .stdout == "rows: 2\n "
338+
339+
340+ _STARTUP_FATAL = (
341+ "Fatal Python error: _Py_HashRandomization_Init: failed to get random "
342+ "numbers to initialize Python\n Python runtime state: preinitialized\n \n "
343+ )
344+
345+
346+ @pytest .mark .parametrize (
347+ "code" ,
348+ [
349+ GOOD ,
350+ 'import pandas as pd\n print(pd.read_csv("your_data.csv")["memo"].tolist())\n ' ,
351+ 'import pandas as pd\n pd.DataFrame().to_csv("your_data.csv")\n ' ,
352+ ],
353+ )
354+ def test_child_that_cannot_start_is_an_infrastructure_failure (monkeypatch , code ):
355+ # Seen on Windows + CPython 3.9: the child died at startup, and each case
356+ # reported an ordinary "generated code exited 1", so the canary and
357+ # overwrite checks passed vacuously.
358+ calls = []
359+
360+ def child_never_started (args , ** kwargs ):
361+ calls .append (args )
362+ return subprocess .CompletedProcess (args , 1 , "" , _STARTUP_FATAL )
363+
364+ monkeypatch .setattr (gc .subprocess , "run" , child_never_started )
365+ result = verify_generated_code (code , _fixture ())
366+ assert not result .passed
367+ assert result .infrastructure_failure
368+ assert "_Py_HashRandomization_Init" in result .infrastructure_failure
369+ assert result .failures == (result .infrastructure_failure ,)
370+ assert "execute" not in result .stages
371+ assert not any ("generated code exited" in f for f in result .failures )
372+ assert len (calls ) == 1 # a startup failure is not retried as a native crash
373+
374+
375+ @pytest .mark .skipif (sys .platform == "win32" , reason = "POSIX shebang interpreter" )
376+ def test_child_exiting_cleanly_without_running_the_harness_fails_closed (tmp_path ):
377+ python = _fake_interpreter (tmp_path , "import sys\n sys.exit(0)\n " )
378+ result = verify_generated_code (GOOD , _fixture (), python = python )
379+ assert not result .passed
380+ assert "exited with code 0 before starting the harness" in (
381+ result .infrastructure_failure or ""
382+ )
383+
384+
385+ def test_normal_run_reports_generated_stdout_without_the_start_marker ():
386+ result = verify_generated_code (GOOD , _fixture ())
387+ assert result .passed , result .failures
388+ assert result .infrastructure_failure is None
389+ assert result .stdout == "rows: 2\n "
0 commit comments