Skip to content

Commit 644aa80

Browse files
author
goweft
committed
fix: OOM integration test — force dirty pages for overcommit kernels\n\nbytearray(n) zero-initializes, but kernels with aggressive overcommit\n(GitHub Actions runners) use copy-on-write zero pages without committing\nreal RAM, so the OOM killer never fires and the test returns exit 0.\n\nFix: allocate b'x' * 10MB in a while-True loop. The non-zero bytes\nliteral forces every page dirty, requiring real physical memory commits.\nThe loop runs until the cgroup memory cap triggers OOM kill (exit 137).\n\nPasses locally (weftbox) and should now pass on GitHub Actions runners\nwhere the original bytearray approach returned exit 0.
1 parent 0c37bc4 commit 644aa80

1 file changed

Lines changed: 12 additions & 6 deletions

File tree

tests/test_integration.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,20 @@ def test_integration_write_to_root_denied():
5757

5858
def test_integration_oom_kill_captured():
5959
"""--memory limit must trigger OOM kill (exit 137) on overshoot."""
60-
# bytearray() touches every byte, so the kernel actually allocates
61-
# and the OOM killer fires. 200 MB allocation against a 64 MB cap.
60+
# bytearray(n) zero-initializes, but kernels with aggressive
61+
# overcommit (e.g. GitHub Actions runners) use copy-on-write zero
62+
# pages without committing real RAM — the OOM killer never fires.
63+
# Fix: allocate b'x' * 10MB in a loop. The bytes literal is
64+
# non-zero, so every page is dirty and the kernel must commit
65+
# physical memory. The loop runs until OOM kills the process.
66+
oom_script = (
67+
"data = []\n"
68+
"while True:\n"
69+
" data.append(b'x' * 10_000_000)\n"
70+
)
6271
result = _docker_run(
6372
"--memory=64m", IMAGE,
64-
"python", "-c", "bytearray(200_000_000)",
73+
"python3", "-c", oom_script,
6574
timeout=30,
6675
)
6776
assert result.returncode == 137, (
@@ -88,9 +97,6 @@ def test_integration_egress_blocked_with_network_none():
8897
f"expected non-zero exit; got 0 (network was reachable). "
8998
f"stdout={result.stdout!r} stderr={result.stderr!r}"
9099
)
91-
# Accept any of the common failure surfaces. The Python urllib call
92-
# surfaces network unreachable / DNS failure depending on the kernel
93-
# and resolver state; what matters is that it can't actually connect.
94100
stderr = result.stderr.decode("utf-8", errors="replace").lower()
95101
expected_signals = (
96102
"network is unreachable",

0 commit comments

Comments
 (0)