{"record":{"id":"42f020882f8978dd","repo":"XTLS/Xray-core","slug":"empty-process-path","errorCode":null,"errorMessage":"empty process path","messagePattern":"empty process path","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"common/net/find_process_darwin.go","lineNumber":296,"sourceCode":"\t\tif value != 0 {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc darwinReadNativeUint32(b []byte) uint32 {\n\treturn *(*uint32)(unsafe.Pointer(&b[0]))\n}\n\nfunc darwinProcessPath(pid int32) (string, error) {\n\tbuf := make([]byte, unix.PathMax)\n\tn, err := darwinProcPIDPath(pid, buf)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif n <= 0 {\n\t\treturn \"\", errors.New(\"empty process path\")\n\t}\n\treturn strings.TrimRight(string(buf[:n]), \"\\x00\"), nil\n}\n\nfunc darwinProcPIDInfo(pid int32, flavor int, arg uint64, buf []byte) (int, error) {\n\tvar ptr unsafe.Pointer\n\tif len(buf) > 0 {\n\t\tptr = unsafe.Pointer(&buf[0])\n\t}\n\n\tr0, _, errno := syscall_syscall6(libc_proc_pidinfo_trampoline_addr, uintptr(pid), uintptr(flavor), uintptr(arg), uintptr(ptr), uintptr(len(buf)), 0)\n\tif errno != 0 {\n\t\treturn 0, errno\n\t}\n\treturn int(r0), nil\n}\n\nfunc darwinProcPIDFDInfo(pid int32, fd int32, flavor int, buf []byte) (int, error) {","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/common/net/find_process_darwin.go#L278-L314","documentation":"darwinProcessPath called proc_pidpath successfully (no syscall error) but it returned a byte count <= 0, i.e. an empty path. This happens when the kernel can see the process but returns no path bytes, for example zombie processes or processes whose image is being torn down.","triggerScenarios":"PID exists in the process table but is a zombie (exited, not yet reaped), so proc_pidpath yields 0 bytes; or a process mid-exec where the path is transiently unavailable.","commonSituations":"High-churn process environments (build systems, CGI-like spawners) where children become zombies between enumeration and path query.","solutions":["Treat as a transient lookup miss: skip process-based rules for this connection","Retry the lookup once after a short delay if the connection persists","Verify with ps -o stat= -p <pid>: a Z status confirms a zombie","Reap children promptly in the application that spawns them"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"func isEmptyProcessPath(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"empty process path\")\n}","tryCatchPattern":"if err != nil && isEmptyProcessPath(err) {\n    // zombie or tearing-down process; skip process rules for this connection\n}","preventionTips":["Expect empty paths for zombie processes in high-churn environments","Reap children promptly in spawning applications"],"tags":["darwin","process-lookup","zombie-process","proc-pidpath"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}