Test binaries leak temporary CODEX_HOME directories after exit
What issue are you seeing?
Codex integration test binaries leave temporary CODEX_HOME directories behind after a normal test process exit.
The leaked directories are named codex-core-tests* and codex-exec-server-tests*. They contain nested arg0 helper directories, lock files, and symlinks to the test binary.
This reproduces on both FreeBSD and WSL2/Linux. On my FreeBSD development system, repeated test runs accumulated 879 codex-core-tests* directories under /tmp.
What steps can reproduce the bug?
Using commit 5c19155cbd93bfa099016e7487259f61669823ff:
- Create an isolated temporary root:
probe_root=$(mktemp -d /tmp/codex-static-leak.XXXXXX)
- From
codex-rs, run one core integration test:
TMPDIR="$probe_root" just test \
-p codex-core \
--test all \
-E 'test(=suite::resume_warning::emits_warning_when_resumed_model_differs)'
- Inspect the temporary root:
find "$probe_root" -maxdepth 5 -printf '%y %p -> %l\n' | sort
After the test exits successfully, multiple codex-core-tests* directories remain. In one WSL2 run, a single filtered test left three directories.
The same lifetime issue affects the exec-server integration test guard.
What is the expected behavior?
Temporary CODEX_HOME directories created by integration test binaries should be removed after a normal process exit.
Forced termination such as SIGKILL does not need to be handled, because process destructors cannot run in that case.
Additional information
Root cause:
codex-rs/core/tests/suite/mod.rs and codex-rs/exec-server/tests/common/mod.rs store TestBinaryDispatchGuard in #[ctor] statics. Rust statics are not dropped at process exit, so the owned tempfile::TempDir values never perform cleanup.
I prepared and tested a candidate fix:
https://github.com/askac/codex/commit/69b91a030206c5a36936d294130e9b8894f8ada8
Full comparison:
https://github.com/openai/codex/compare/main...askac:fix-test-binary-tempdir-cleanup
The candidate fix:
- stores each guard in a regular static
Mutex<Option<_>>; - takes and drops the guard from a destructor on normal exit;
- avoids holding the mutex while the exec-server test mode is running;
- drops the nested arg0 guard before its parent temporary CODEX_HOME, which is important on Windows while the lock file is open;
- adds a self-reexec regression test using an isolated temporary root.
Verification:
- WSL2/Linux core regression test: passed;
- FreeBSD exec-server relay integration test: passed;
- no new
codex-core-tests*orcodex-exec-server-tests*directories remained after the successful patched test runs.
The repository currently limits pull request creation to collaborators, so I am providing the analysis, reproduction, and public candidate fix here first.