Skip to content

Commit f33ed4d

Browse files
georgeh0claude
andcommitted
fix: avoid os.kill on Windows due to CPython C exception state corruption
os.kill(pid, 0) on Windows corrupts CPython C-level exception state even after the raised OSError is caught. This causes subsequent calls to C built-ins (time.monotonic, time.sleep) to raise SystemError. Use ctypes OpenProcess instead, which is the proper Win32 API for checking process existence. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d4fcdb0 commit f33ed4d

1 file changed

Lines changed: 13 additions & 5 deletions

File tree

src/cocoindex_code/client.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,18 +220,26 @@ def _find_ccc_executable() -> str | None:
220220

221221
def _pid_alive(pid: int) -> bool:
222222
"""Return True if *pid* is still running."""
223+
if sys.platform == "win32":
224+
# Avoid os.kill(pid, 0) on Windows — it has a CPython bug that corrupts
225+
# the C-level exception state, causing subsequent C function calls
226+
# (time.monotonic, time.sleep) to raise SystemError even after the
227+
# OSError is caught. Use OpenProcess via ctypes instead.
228+
import ctypes
229+
230+
kernel32 = ctypes.windll.kernel32 # type: ignore[attr-defined]
231+
handle = kernel32.OpenProcess(0x1000, False, pid) # PROCESS_QUERY_LIMITED_INFORMATION
232+
if handle:
233+
kernel32.CloseHandle(handle)
234+
return True
235+
return False
223236
try:
224237
os.kill(pid, 0) # signal 0: check existence without killing
225238
return True
226239
except ProcessLookupError:
227240
return False
228241
except PermissionError:
229242
return True # process exists but we can't signal it
230-
except (OSError, SystemError):
231-
# On Windows, os.kill(pid, 0) can raise SystemError or unexpected OSError
232-
# variants (e.g. WinError 87 "The parameter is incorrect") for PIDs that
233-
# have exited but whose handles haven't been fully released.
234-
return False
235243

236244

237245
def stop_daemon() -> None:

0 commit comments

Comments
 (0)