From 5b59ab3d9cff77cf62aeb342a3c02297311aa49e Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 19 Sep 2018 18:10:38 -0500 Subject: [PATCH] Add workaround to env_get_pwd_slash() for cases where PWD is not set There's been no reproducible case entered for #5080, but the stack trace indicates the problem is with env_get_pwd_slash() returning an empty string, which isn't a string that terminates in `/`. In addition to making the failure case to return the path `./` (which has the benefit of having the same meaning as $PWD), trying a little bit harder to retrieve the real PWD by using getcwd(3). While get_current_dir(3) is documented as relying on PWD, getcwd(3) does not mention any such caveats, so it's possible that it will work even if something is breaking PWD. Just a thought, but it's possible if due to some recursion PWD surpassed some predetermined value (maybe PATH_MAX) that PWD (on certain platforms or under certain enivronments) won't be set (hence the code that deals with ERANGE errors from the getcwd(3) call). Closes #5080. --- src/env.cpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/env.cpp b/src/env.cpp index 77f65b7bc..fc00031f1 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -698,10 +698,36 @@ void env_set_read_limit() { wcstring env_get_pwd_slash() { auto pwd_var = env_get(L"PWD"); - if (pwd_var.missing_or_empty()) { - return L""; + wcstring pwd; + if (!pwd_var.missing_or_empty()) { + pwd = pwd_var->as_string(); } - wcstring pwd = pwd_var->as_string(); + else { + // Not sure how we can end up here, but it's possible. + // See https://github.com/fish-shell/fish-shell/issues/5080 + // Perhaps it can happen on some platforms if the path is too long? + std::vector path; + bool cwd_success = false; + for (int i = 1; !cwd_success && i <= 10; ++i) { + path.resize(PATH_MAX * i); + if (getcwd(&path[0], PATH_MAX * i) == nullptr) { + if (errno == ERANGE) { + // buffer is not big enough, try again (up to a point) + continue; + } + debug(1, "getcwd() failed with errno %d", errno); + // . but with a trailing slash, because that's what this function does + return L"./"; + } + cwd_success = true; + } + if (!cwd_success) { + debug(1, "getcwd() path too long!"); + return L"./"; + } + pwd = str2wcstring(path.data()); + } + if (!string_suffixes_string(L"/", pwd)) { pwd.push_back(L'/'); }