From 1cce5759c7d202625d2716df4c1993b7f1d0114b Mon Sep 17 00:00:00 2001 From: Artemis Tosini Date: Sat, 30 Mar 2024 21:47:59 -0400 Subject: [PATCH] gc: Read per-thread cwds on Darwin --- src/libstore/gc.cc | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 02502b945..0342965b3 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -431,12 +431,12 @@ static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked) auto storePathRegex = std::regex(quoteRegexChars(storeDir) + R"(/[0-9a-z]+[0-9a-zA-Z\+\-\._\?=]*)"); int pidBufSize = proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0); - if (pidBufSize <= 0 || pidBufSize % sizeof(int) != 0) + if (pidBufSize <= 0) throw SysError("Listing PIDs"); std::vector pids(pidBufSize / sizeof(int)); - pidBufSize = proc_listpids(PROC_ALL_PIDS, 0, pids.data(), pidBufSize); - if (pidBufSize <= 0 || pidBufSize % sizeof(int) != 0) + pidBufSize = proc_listpids(PROC_ALL_PIDS, 0, pids.data(), pids.size() * sizeof(int)); + if (pidBufSize <= 0) throw SysError("Listing PIDs"); pids.resize(pidBufSize / sizeof(int)); @@ -456,12 +456,12 @@ static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked) // File descriptors int fdBufSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, nullptr, 0); - if (fdBufSize <= 0 || fdBufSize % sizeof(struct proc_fdinfo) != 0) { + if (fdBufSize <= 0) { if ((errno == ESRCH) || (errno == EPERM)) continue; throw SysError("Listing pid %1% file descriptors", pid); } std::vector fds(fdBufSize / sizeof(struct proc_fdinfo)); - fdBufSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds.data(), fdBufSize); + fdBufSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fds.data(), fds.size() * sizeof(struct proc_fdinfo)); if (fdBufSize <= 0) { if ((errno == ESRCH) || (errno == EPERM)) continue; throw SysError("Listing pid %1% file descriptors", pid); @@ -517,13 +517,13 @@ static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked) int sysctlName[3] = {CTL_KERN, KERN_PROCARGS2, pid}; size_t argsSize = 0; if (sysctl(sysctlName, 3, nullptr, &argsSize, nullptr, 0) < 0) { - throw SysError("Reading pid %1% arguments"); + throw SysError("Reading pid %1% arguments", pid); } std::vector args(argsSize); if (sysctl(sysctlName, 3, args.data(), &argsSize, nullptr, 0) < 0) { - throw SysError("Reading pid %1% arguments"); + throw SysError("Reading pid %1% arguments", pid); } if (argsSize < args.size()) @@ -534,8 +534,32 @@ static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked) unchecked[i->str()].emplace("{libproc/args}"); - // TODO: per-thread cwds (apparently exist but I don't see them much) + // Per-thread working directories + struct proc_taskallinfo taskAllInfo; + if (proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &taskAllInfo, sizeof(taskAllInfo)) <= 0) { + if ((errno == ESRCH) || (errno == EPERM)) continue; + throw SysError("Reading pid %1% tasks", pid); + } + // If the process doesn't have the per-thread cwd flag then we already have the + // process-wide cwd from PROC_PIDVNODEPATHINFO + if (taskAllInfo.pbsd.pbi_flags & PROC_FLAG_THCWD) { + std::vector tids(taskAllInfo.ptinfo.pti_threadnum); + int tidBufSize = proc_pidinfo(pid, PROC_PIDLISTTHREADS, 0, tids.data(), tids.size() * sizeof(uint64_t)); + if (tidBufSize <= 0) { + if ((errno == ESRCH) || (errno == EPERM)) continue; + throw SysError("Listing pid %1% threads", pid); + } + + for (auto tid: tids) { + struct proc_threadwithpathinfo threadPathInfo; + if (proc_pidinfo(pid, PROC_PIDTHREADPATHINFO, tid, &threadPathInfo, sizeof(threadPathInfo)) <= 0) { + if ((errno == ESRCH) || (errno == EPERM)) continue; + throw SysError("Reading pid %1% thread %2% cwd", pid, tid); + } + unchecked[std::string(threadPathInfo.pvip.vip_path)].emplace("{libproc/threadcwd}"); + } + } } } #endif