Fix file handle leak in _spawn_hermes_action

The log file opened for subprocess output was never explicitly closed.
After Popen inherits the file descriptor, the Python file object should
be closed. If Popen() raised an exception, the file handle would also
leak since close() was never reached.

Wrap the Popen creation in try/except/else to ensure the file handle is
always closed — on success (subprocess inherits the fd) and on failure.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ricardo-M-L 2026-04-22 12:38:58 +08:00
parent ff9752410a
commit 2c62c55e56

View file

@ -595,28 +595,34 @@ def _spawn_hermes_action(subcommand: List[str], name: str) -> subprocess.Popen:
_ACTION_LOG_DIR.mkdir(parents=True, exist_ok=True)
log_path = _ACTION_LOG_DIR / log_file_name
log_file = open(log_path, "ab", buffering=0)
log_file.write(
f"\n=== {name} started {time.strftime('%Y-%m-%d %H:%M:%S')} ===\n".encode()
)
cmd = [sys.executable, "-m", "hermes_cli.main", *subcommand]
popen_kwargs: Dict[str, Any] = {
"cwd": str(PROJECT_ROOT),
"stdin": subprocess.DEVNULL,
"stdout": log_file,
"stderr": subprocess.STDOUT,
"env": {**os.environ, "HERMES_NONINTERACTIVE": "1"},
}
if sys.platform == "win32":
popen_kwargs["creationflags"] = (
subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore[attr-defined]
| getattr(subprocess, "DETACHED_PROCESS", 0)
try:
log_file.write(
f"\n=== {name} started {time.strftime('%Y-%m-%d %H:%M:%S')} ===\n".encode()
)
else:
popen_kwargs["start_new_session"] = True
proc = subprocess.Popen(cmd, **popen_kwargs)
cmd = [sys.executable, "-m", "hermes_cli.main", *subcommand]
popen_kwargs: Dict[str, Any] = {
"cwd": str(PROJECT_ROOT),
"stdin": subprocess.DEVNULL,
"stdout": log_file,
"stderr": subprocess.STDOUT,
"env": {**os.environ, "HERMES_NONINTERACTIVE": "1"},
}
if sys.platform == "win32":
popen_kwargs["creationflags"] = (
subprocess.CREATE_NEW_PROCESS_GROUP # type: ignore[attr-defined]
| getattr(subprocess, "DETACHED_PROCESS", 0)
)
else:
popen_kwargs["start_new_session"] = True
proc = subprocess.Popen(cmd, **popen_kwargs)
except Exception:
log_file.close()
raise
else:
log_file.close()
_ACTION_PROCS[name] = proc
return proc