mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-09 11:30:35 +00:00
Force use of getenv/setenv directly from libc to avoid bash override
* Bash overrides getenv/setenv to look up its own variable set, but breaks since we need to modify the environment before main() when it initialises its variable set. Instead what happens is the first setenv initialises that variable in a blank set and so all subsequent environment variables are NULL. Then in main() the variable set gets initialised from environ, removing any changes that were made.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <elf.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ptrace.h>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<EnvironmentModification> &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<char *> &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<RDResult, uint32_t> Process::LaunchAndInjectIntoProcess(
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user