mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-10 20:10:33 +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";
|
RENDERDOC_VULKAN_JSON_SUFFIX) ".json";
|
||||||
case LayerPath::home:
|
case LayerPath::home:
|
||||||
{
|
{
|
||||||
const char *xdg = getenv("XDG_DATA_HOME");
|
rdcstr xdg = Process::GetEnvVariable("XDG_DATA_HOME");
|
||||||
if(xdg && FileIO::exists(xdg))
|
if(!xdg.empty() && FileIO::exists(xdg))
|
||||||
return rdcstr(xdg) + "/vulkan/implicit_layer.d/renderdoc_capture" STRINGIZE(
|
return xdg + "/vulkan/implicit_layer.d/renderdoc_capture" STRINGIZE(
|
||||||
RENDERDOC_VULKAN_JSON_SUFFIX) ".json";
|
RENDERDOC_VULKAN_JSON_SUFFIX) ".json";
|
||||||
|
|
||||||
const char *home_path = getenv("HOME");
|
rdcstr home_path = Process::GetEnvVariable("HOME");
|
||||||
return rdcstr(home_path != NULL ? home_path : "") +
|
return home_path + "/.local/share/vulkan/implicit_layer.d/renderdoc_capture" STRINGIZE(
|
||||||
"/.local/share/vulkan/implicit_layer.d/renderdoc_capture" STRINGIZE(
|
RENDERDOC_VULKAN_JSON_SUFFIX) ".json";
|
||||||
RENDERDOC_VULKAN_JSON_SUFFIX) ".json";
|
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ void ResetHookingEnvVars();
|
|||||||
void StopAtMainInChild();
|
void StopAtMainInChild();
|
||||||
bool StopChildAtMain(pid_t childPid);
|
bool StopChildAtMain(pid_t childPid);
|
||||||
void ResumeProcess(pid_t childPid, uint32_t delay = 0);
|
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
|
// 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();
|
pid_t ret = realfork();
|
||||||
if(ret == 0)
|
if(ret == 0)
|
||||||
unsetenv(RENDERDOC_VULKAN_LAYER_VAR);
|
direct_setenv(RENDERDOC_VULKAN_LAYER_VAR, "", true);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
@@ -717,9 +718,30 @@ bool OSUtility::DebuggerPresent()
|
|||||||
return debuggerPresent;
|
return debuggerPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using PFN_getenv = decltype(&getenv);
|
||||||
|
|
||||||
rdcstr Process::GetEnvVariable(const rdcstr &name)
|
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();
|
return val ? val : rdcstr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -596,18 +596,18 @@ rdcstr GetTempRootPath()
|
|||||||
rdcstr GetAppFolderFilename(const rdcstr &filename)
|
rdcstr GetAppFolderFilename(const rdcstr &filename)
|
||||||
{
|
{
|
||||||
passwd *pw = getpwuid(getuid());
|
passwd *pw = getpwuid(getuid());
|
||||||
const char *homedir = pw ? pw->pw_dir : NULL;
|
rdcstr homedir = pw ? pw->pw_dir : "";
|
||||||
|
|
||||||
if(!homedir)
|
if(homedir.empty())
|
||||||
homedir = getenv("HOME");
|
homedir = Process::GetEnvVariable("HOME");
|
||||||
|
|
||||||
if(!homedir)
|
if(homedir.empty())
|
||||||
{
|
{
|
||||||
RDCERR("Can't get HOME directory, defaulting to '/' instead");
|
RDCERR("Can't get HOME directory, defaulting to '/' instead");
|
||||||
homedir = "";
|
homedir = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
rdcstr ret = rdcstr(homedir) + "/.renderdoc/";
|
rdcstr ret = homedir + "/.renderdoc/";
|
||||||
|
|
||||||
mkdir(ret.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
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 it's ~/... then replace with $HOME and return
|
||||||
if(path[0] == '~' && path[1] == '/')
|
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 it's ~user/... then use getpwname
|
||||||
if(path[0] == '~')
|
if(path[0] == '~')
|
||||||
@@ -341,6 +341,29 @@ static rdcstr shellExpand(const rdcstr &in)
|
|||||||
return path;
|
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)
|
void Process::RegisterEnvironmentModification(const EnvironmentModification &modif)
|
||||||
{
|
{
|
||||||
GetEnvModifications().push_back(modif);
|
GetEnvModifications().push_back(modif);
|
||||||
@@ -397,7 +420,7 @@ void ApplyEnvironmentModifications(rdcarray<EnvironmentModification> &modificati
|
|||||||
|
|
||||||
ApplySingleEnvMod(m, value);
|
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()
|
void ResetHookingEnvVars()
|
||||||
{
|
{
|
||||||
setenv(LIB_PATH_ENV_VAR, Process::GetEnvVariable("RENDERDOC_ORIGLIBPATH").c_str(), true);
|
direct_setenv(LIB_PATH_ENV_VAR, Process::GetEnvVariable("RENDERDOC_ORIGLIBPATH").c_str(), true);
|
||||||
setenv(PRELOAD_ENV_VAR, Process::GetEnvVariable("RENDERDOC_ORIGPRELOAD").c_str(), true);
|
direct_setenv(PRELOAD_ENV_VAR, Process::GetEnvVariable("RENDERDOC_ORIGPRELOAD").c_str(), true);
|
||||||
unsetenv("RENDERDOC_ORIGLIBPATH");
|
direct_setenv("RENDERDOC_ORIGLIBPATH", "", true);
|
||||||
unsetenv("RENDERDOC_ORIGPRELOAD");
|
direct_setenv("RENDERDOC_ORIGPRELOAD", "", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
rdcpair<RDResult, uint32_t> Process::LaunchAndInjectIntoProcess(
|
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
|
// 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
|
// Return "" if no exectuable found in the PATH list
|
||||||
char *pathEnvVar = getenv("PATH");
|
rdcstr pathEnvVar = Process::GetEnvVariable("PATH");
|
||||||
if(!pathEnvVar)
|
if(pathEnvVar.empty())
|
||||||
return filePath;
|
return filePath;
|
||||||
|
|
||||||
// Make a copy of our PATH so strtok can insert NULL without actually changing env
|
// Make a copy of our PATH so strtok can insert NULL without actually changing env
|
||||||
char *localPath = new char[strlen(pathEnvVar) + 1];
|
char *localPath = pathEnvVar.data();
|
||||||
strcpy(localPath, pathEnvVar);
|
|
||||||
|
|
||||||
const char *pathSeparator = ":";
|
const char *pathSeparator = ":";
|
||||||
const char *path = strtok(localPath, pathSeparator);
|
const char *path = strtok(localPath, pathSeparator);
|
||||||
@@ -129,7 +128,6 @@ rdcstr FindFileInPath(const rdcstr &fileName)
|
|||||||
path = strtok(NULL, pathSeparator);
|
path = strtok(NULL, pathSeparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] localPath;
|
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,10 +208,10 @@ void GetDefaultFiles(const rdcstr &logBaseName, rdcstr &capture_filename, rdcstr
|
|||||||
|
|
||||||
strcpy(temp_folder, GetTempRootPath().c_str());
|
strcpy(temp_folder, GetTempRootPath().c_str());
|
||||||
|
|
||||||
char *temp_override = getenv("RENDERDOC_TEMP");
|
rdcstr temp_override = Process::GetEnvVariable("RENDERDOC_TEMP");
|
||||||
if(temp_override && temp_override[0] == '/')
|
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);
|
size_t len = strlen(temp_folder);
|
||||||
while(temp_folder[len - 1] == '/')
|
while(temp_folder[len - 1] == '/')
|
||||||
temp_folder[--len] = 0;
|
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);
|
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
|
// set by UI when launching programs so all logging goes to the same file
|
||||||
char *logfile_override = getenv("RENDERDOC_DEBUG_LOG_FILE");
|
rdcstr logfile_override = Process::GetEnvVariable("RENDERDOC_DEBUG_LOG_FILE");
|
||||||
if(logfile_override)
|
if(!logfile_override.empty())
|
||||||
logging_filename = rdcstr(logfile_override);
|
logging_filename = logfile_override;
|
||||||
else
|
else
|
||||||
logging_filename = StringFormat::Fmt(
|
logging_filename = StringFormat::Fmt(
|
||||||
"%s/RenderDoc/%s_%04d.%02d.%02d_%02d.%02d.%02d.log", temp_folder, logBaseName.c_str(),
|
"%s/RenderDoc/%s_%04d.%02d.%02d_%02d.%02d.%02d.log", temp_folder, logBaseName.c_str(),
|
||||||
|
|||||||
Reference in New Issue
Block a user