From 89d360aa4ab9cb56e2d81542c5957eb6fcb15055 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Sun, 19 Apr 2026 06:21:50 +0200 Subject: [PATCH] Rewrote Linux edition of proc_self_dirname() to handle any symlink length. This make sure the method work also when the program is located in deep or long file paths, longer than both PATH_MAX and "getconf PATH_MAX .". Use the same code on GNU Hurd, where it now work. I am not sure how to test this in a platform independent way. --- kernel/yosys.cc | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 29fcd48d8..b3688b77b 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -471,17 +471,30 @@ struct TclPass : public Pass { #endif -#if defined(__linux__) || defined(__CYGWIN__) +#if defined(__linux__) || defined(__CYGWIN__) || defined(__gnu_hurd__) std::string proc_self_dirname() { - char path[PATH_MAX]; - ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path)); + std::string path(4096, '\0'); + ssize_t buflen = -1; + // Double until sucess, while avoiding endless loop. Give up + // when symlink is longer than 4096*(2^30) = 4398046511104 + // bytes. + for (int tries = 30; 0 < tries; tries--) { + buflen = readlink("/proc/self/exe", path.data(), path.size()); + if (buflen < (ssize_t)path.size()) + break; + else + path.resize(path.size() * 2); + } if (buflen < 0) { log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno)); + path.resize(0); + } else { + while (buflen > 0 && path[buflen-1] != '/') + buflen--; + path.resize(buflen); } - while (buflen > 0 && path[buflen-1] != '/') - buflen--; - return std::string(path, buflen); + return path; } #elif defined(__FreeBSD__) || defined(__NetBSD__) std::string proc_self_dirname()