diff --git a/renderdoc/driver/vulkan/vk_posix.cpp b/renderdoc/driver/vulkan/vk_posix.cpp index 75a65f17f..32fed985e 100644 --- a/renderdoc/driver/vulkan/vk_posix.cpp +++ b/renderdoc/driver/vulkan/vk_posix.cpp @@ -373,15 +373,14 @@ rdcstr LayerRegistrationPath(LayerPath path) RENDERDOC_VULKAN_JSON_SUFFIX) ".json"; case LayerPath::home: { - const char *xdg = getenv("XDG_DATA_HOME"); - if(xdg && FileIO::exists(xdg)) - return rdcstr(xdg) + "/vulkan/implicit_layer.d/renderdoc_capture" STRINGIZE( - RENDERDOC_VULKAN_JSON_SUFFIX) ".json"; + rdcstr xdg = Process::GetEnvVariable("XDG_DATA_HOME"); + if(!xdg.empty() && FileIO::exists(xdg)) + return xdg + "/vulkan/implicit_layer.d/renderdoc_capture" STRINGIZE( + RENDERDOC_VULKAN_JSON_SUFFIX) ".json"; - const char *home_path = getenv("HOME"); - return rdcstr(home_path != NULL ? home_path : "") + - "/.local/share/vulkan/implicit_layer.d/renderdoc_capture" STRINGIZE( - RENDERDOC_VULKAN_JSON_SUFFIX) ".json"; + rdcstr home_path = Process::GetEnvVariable("HOME"); + return home_path + "/.local/share/vulkan/implicit_layer.d/renderdoc_capture" STRINGIZE( + RENDERDOC_VULKAN_JSON_SUFFIX) ".json"; } default: break; } diff --git a/renderdoc/os/posix/linux/linux_hook.cpp b/renderdoc/os/posix/linux/linux_hook.cpp index c28ea0f7d..f6d2ecebf 100644 --- a/renderdoc/os/posix/linux/linux_hook.cpp +++ b/renderdoc/os/posix/linux/linux_hook.cpp @@ -102,6 +102,7 @@ void ResetHookingEnvVars(); void StopAtMainInChild(); bool StopChildAtMain(pid_t childPid); void ResumeProcess(pid_t childPid, uint32_t delay = 0); +int direct_setenv(const char *name, const char *value, int overwrite); /////////////////////////////////////////////////////////////// // exec hooks - we have to hook each variant since if the application calls the 'real' one of a @@ -293,7 +294,7 @@ __attribute__((visibility("default"))) pid_t fork() pid_t ret = realfork(); if(ret == 0) - unsetenv(RENDERDOC_VULKAN_LAYER_VAR); + direct_setenv(RENDERDOC_VULKAN_LAYER_VAR, "", true); return ret; } diff --git a/renderdoc/os/posix/linux/linux_process.cpp b/renderdoc/os/posix/linux/linux_process.cpp index 7be046836..694275acb 100644 --- a/renderdoc/os/posix/linux/linux_process.cpp +++ b/renderdoc/os/posix/linux/linux_process.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. ******************************************************************************/ +#include #include #include #include @@ -717,9 +718,30 @@ bool OSUtility::DebuggerPresent() return debuggerPresent; } +using PFN_getenv = decltype(&getenv); + rdcstr Process::GetEnvVariable(const rdcstr &name) { - const char *val = getenv(name.c_str()); + const char *val = NULL; + // try to bypass any hooks to ensure we don't break (looking at you bash) + + static PFN_getenv dyn_getenv = NULL; + static bool checked = false; + if(!checked) + { + checked = true; + void *libc = dlopen("libc.so.6", RTLD_NOLOAD | RTLD_GLOBAL | RTLD_NOW); + if(libc) + { + dyn_getenv = (PFN_getenv)dlsym(libc, "getenv"); + } + } + + if(dyn_getenv) + val = dyn_getenv(name.c_str()); + else + val = getenv(name.c_str()); + return val ? val : rdcstr(); } diff --git a/renderdoc/os/posix/linux/linux_stringio.cpp b/renderdoc/os/posix/linux/linux_stringio.cpp index 5228a4483..2f37b4f23 100644 --- a/renderdoc/os/posix/linux/linux_stringio.cpp +++ b/renderdoc/os/posix/linux/linux_stringio.cpp @@ -596,18 +596,18 @@ rdcstr GetTempRootPath() rdcstr GetAppFolderFilename(const rdcstr &filename) { passwd *pw = getpwuid(getuid()); - const char *homedir = pw ? pw->pw_dir : NULL; + rdcstr homedir = pw ? pw->pw_dir : ""; - if(!homedir) - homedir = getenv("HOME"); + if(homedir.empty()) + homedir = Process::GetEnvVariable("HOME"); - if(!homedir) + if(homedir.empty()) { RDCERR("Can't get HOME directory, defaulting to '/' instead"); homedir = ""; } - rdcstr ret = rdcstr(homedir) + "/.renderdoc/"; + rdcstr ret = homedir + "/.renderdoc/"; mkdir(ret.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); diff --git a/renderdoc/os/posix/posix_process.cpp b/renderdoc/os/posix/posix_process.cpp index 45bcddbc7..802c2a804 100644 --- a/renderdoc/os/posix/posix_process.cpp +++ b/renderdoc/os/posix/posix_process.cpp @@ -308,7 +308,7 @@ static rdcstr shellExpand(const rdcstr &in) // if it's ~/... then replace with $HOME and return if(path[0] == '~' && path[1] == '/') - return rdcstr(getenv("HOME")) + path.substr(1); + return Process::GetEnvVariable("HOME") + path.substr(1); // if it's ~user/... then use getpwname if(path[0] == '~') @@ -341,6 +341,29 @@ static rdcstr shellExpand(const rdcstr &in) return path; } +using PFN_setenv = decltype(&setenv); + +int direct_setenv(const char *name, const char *value, int overwrite) +{ +// on linux try to bypass any hooks to ensure we don't break (looking at you bash) +#if ENABLED(RDOC_LINUX) + static PFN_setenv dyn_setenv = NULL; + static bool checked = false; + if(!checked) + { + checked = true; + void *libc = dlopen("libc.so.6", RTLD_NOLOAD | RTLD_GLOBAL | RTLD_NOW); + if(libc) + dyn_setenv = (PFN_setenv)dlsym(libc, "setenv"); + } + + if(dyn_setenv) + return dyn_setenv(name, value, overwrite); +#endif + + return setenv(name, value, overwrite); +} + void Process::RegisterEnvironmentModification(const EnvironmentModification &modif) { GetEnvModifications().push_back(modif); @@ -397,7 +420,7 @@ void ApplyEnvironmentModifications(rdcarray &modificati ApplySingleEnvMod(m, value); - setenv(m.name.c_str(), value.c_str(), true); + direct_setenv(m.name.c_str(), value.c_str(), true); } } @@ -875,10 +898,10 @@ void GetHookedEnvp(char *const *envp, rdcstr &envpStr, rdcarray &modifie void ResetHookingEnvVars() { - setenv(LIB_PATH_ENV_VAR, Process::GetEnvVariable("RENDERDOC_ORIGLIBPATH").c_str(), true); - setenv(PRELOAD_ENV_VAR, Process::GetEnvVariable("RENDERDOC_ORIGPRELOAD").c_str(), true); - unsetenv("RENDERDOC_ORIGLIBPATH"); - unsetenv("RENDERDOC_ORIGPRELOAD"); + direct_setenv(LIB_PATH_ENV_VAR, Process::GetEnvVariable("RENDERDOC_ORIGLIBPATH").c_str(), true); + direct_setenv(PRELOAD_ENV_VAR, Process::GetEnvVariable("RENDERDOC_ORIGPRELOAD").c_str(), true); + direct_setenv("RENDERDOC_ORIGLIBPATH", "", true); + direct_setenv("RENDERDOC_ORIGPRELOAD", "", true); } rdcpair Process::LaunchAndInjectIntoProcess( diff --git a/renderdoc/os/posix/posix_stringio.cpp b/renderdoc/os/posix/posix_stringio.cpp index c29b5cecf..64c7800fd 100644 --- a/renderdoc/os/posix/posix_stringio.cpp +++ b/renderdoc/os/posix/posix_stringio.cpp @@ -107,13 +107,12 @@ rdcstr FindFileInPath(const rdcstr &fileName) // Search the PATH directory list for the application (like shell which) to get the absolute path // Return "" if no exectuable found in the PATH list - char *pathEnvVar = getenv("PATH"); - if(!pathEnvVar) + rdcstr pathEnvVar = Process::GetEnvVariable("PATH"); + if(pathEnvVar.empty()) return filePath; // Make a copy of our PATH so strtok can insert NULL without actually changing env - char *localPath = new char[strlen(pathEnvVar) + 1]; - strcpy(localPath, pathEnvVar); + char *localPath = pathEnvVar.data(); const char *pathSeparator = ":"; const char *path = strtok(localPath, pathSeparator); @@ -129,7 +128,6 @@ rdcstr FindFileInPath(const rdcstr &fileName) path = strtok(NULL, pathSeparator); } - delete[] localPath; return filePath; } @@ -210,10 +208,10 @@ void GetDefaultFiles(const rdcstr &logBaseName, rdcstr &capture_filename, rdcstr strcpy(temp_folder, GetTempRootPath().c_str()); - char *temp_override = getenv("RENDERDOC_TEMP"); - if(temp_override && temp_override[0] == '/') + rdcstr temp_override = Process::GetEnvVariable("RENDERDOC_TEMP"); + if(!temp_override.empty() && temp_override[0] == '/') { - strncpy(temp_folder, temp_override, sizeof(temp_folder) - 1); + strncpy(temp_folder, temp_override.c_str(), sizeof(temp_folder) - 1); size_t len = strlen(temp_folder); while(temp_folder[len - 1] == '/') temp_folder[--len] = 0; @@ -224,9 +222,9 @@ void GetDefaultFiles(const rdcstr &logBaseName, rdcstr &capture_filename, rdcstr 1900 + now.tm_year, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min); // set by UI when launching programs so all logging goes to the same file - char *logfile_override = getenv("RENDERDOC_DEBUG_LOG_FILE"); - if(logfile_override) - logging_filename = rdcstr(logfile_override); + rdcstr logfile_override = Process::GetEnvVariable("RENDERDOC_DEBUG_LOG_FILE"); + if(!logfile_override.empty()) + logging_filename = logfile_override; else logging_filename = StringFormat::Fmt( "%s/RenderDoc/%s_%04d.%02d.%02d_%02d.%02d.%02d.log", temp_folder, logBaseName.c_str(),