From 462442a293f989f0731eca14df5c7c0f0fe407bd Mon Sep 17 00:00:00 2001 From: Jonathan Marler Date: Wed, 4 Apr 2018 20:03:00 -0600 Subject: [PATCH] Maintain same environment for dmd -run Fix issue 18729 --- src/dmd/link.d | 68 ++++++++++++++++++++++++---- src/dmd/mars.d | 3 +- test/runnable/extra-files/printenv.d | 11 +++++ test/runnable/sameenv.sh | 10 ++++ 4 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 test/runnable/extra-files/printenv.d create mode 100644 test/runnable/sameenv.sh diff --git a/src/dmd/link.d b/src/dmd/link.d index 33b7f079158..f6d3b3bef11 100644 --- a/src/dmd/link.d +++ b/src/dmd/link.d @@ -32,6 +32,23 @@ version (Windows) extern (C) int putenv(const char*); version (Windows) extern (C) int spawnlp(int, const char*, const char*, const char*, const char*); version (Windows) extern (C) int spawnl(int, const char*, const char*, const char*, const char*); version (Windows) extern (C) int spawnv(int, const char*, const char**); + +string dgetenv(const(char)* name) +{ + auto result = getenv(name); + return cast(string)result[0 .. strlen(result)]; +} +int dputenv(const char[] name, const char[] value) +{ + auto fullLength = name.length + 1 + value.length; + auto buffer = cast(char*)alloca(fullLength + 1); + buffer[0 .. name.length] = name[]; + buffer[name.length] = '='; + buffer[name.length + 1 .. fullLength ] = value[]; + buffer[fullLength] = '\0'; + return putenv(buffer); +} + version (CRuntime_Microsoft) { // until the new windows bindings are available when building dmd. @@ -151,6 +168,37 @@ version (Posix) } } +/** +Use to restore an environment variable when this structure goes out of scope. +*/ +struct EnvRestore(string varName) +{ + private string savedValue; + private bool restore; + + /** + Access the saved environment variable value. + */ + string getSavedValue() const { return savedValue; } + + /** + Call before the overriding the environment variable to save and restore it later. + */ + void saveToRestoreLater() + { + savedValue = dgetenv(varName); + restore = true; + } + + ~this() + { + if (restore) + { + dputenv(varName, savedValue); + } + } +} + /***************************** * Run the linker. Return status of execution. */ @@ -264,8 +312,9 @@ public int runLINK() const(char)* linkcmd = getenv(global.params.is64bit ? "LINKCMD64" : "LINKCMD"); if (!linkcmd) linkcmd = getenv("LINKCMD"); // backward compatible + auto restorePATH = EnvRestore!"PATH"(); if (!linkcmd) - linkcmd = vsopt.linkerPath(global.params.is64bit); + linkcmd = vsopt.linkerPath(global.params.is64bit, restorePATH); int status = executecmd(linkcmd, p); if (lnkfilename) @@ -738,15 +787,16 @@ version (Windows) { int status; size_t len; + auto restore_CMDLINE = EnvRestore!"_CMDLINE"(); + if (global.params.verbose) message("%s %s", cmd, args); if (!global.params.mscoff) { if ((len = strlen(args)) > 255) { - char* q = cast(char*)alloca(8 + len + 1); - sprintf(q, "_CMDLINE=%s", args); - status = putenv(q); + restore_CMDLINE.saveToRestoreLater(); + status = dputenv("_CMDLINE", args[0 .. len]); if (status == 0) { args = "@_CMDLINE"; @@ -1018,7 +1068,7 @@ version (Windows) * Returns: * absolute path to link.exe, just "link.exe" if not found */ - const(char)* linkerPath(bool x64) + const(char)* linkerPath(bool x64, ref EnvRestore!"PATH" restorePATH) { const(char)* addpath; if (auto p = getVCBinDir(x64, addpath)) @@ -1030,15 +1080,15 @@ version (Windows) { // debug info needs DLLs from $(VSInstallDir)\Common7\IDE for most linker versions // so prepend it too the PATH environment variable - const char* path = getenv("PATH"); - const pathlen = strlen(path); + restorePATH.saveToRestoreLater(); + const char[] path = restorePATH.getSavedValue; const addpathlen = strlen(addpath); - char* npath = cast(char*)mem.xmalloc(5 + pathlen + 1 + addpathlen + 1); + char* npath = cast(char*)mem.xmalloc(5 + path.length + 1 + addpathlen + 1); memcpy(npath, "PATH=".ptr, 5); memcpy(npath + 5, addpath, addpathlen); npath[5 + addpathlen] = ';'; - memcpy(npath + 5 + addpathlen + 1, path, pathlen + 1); + memcpy(npath + 5 + addpathlen + 1, path.ptr, path.length + 1); putenv(npath); } return cmdbuf.extractString(); diff --git a/src/dmd/mars.d b/src/dmd/mars.d index 1a7ad3f9eb5..9a9ad2781b1 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -266,7 +266,8 @@ private int tryMain(size_t argc, const(char)** argv) sections.push(envsection.ptr); parseConfFile(&environment, global.inifilename, inifilepath, inifile.len, inifile.buffer, §ions); getenv_setargv(readFromEnv(&environment, "DFLAGS"), &arguments); - updateRealEnvironment(&environment); + // TODO: not sure why dmd is doing this + //updateRealEnvironment(&environment); environment.reset(1); // don't need environment cache any more if (parseCommandLine(arguments, argc, global.params, files)) diff --git a/test/runnable/extra-files/printenv.d b/test/runnable/extra-files/printenv.d new file mode 100644 index 00000000000..b8536d200c0 --- /dev/null +++ b/test/runnable/extra-files/printenv.d @@ -0,0 +1,11 @@ +import std.array, std.stdio, std.process, std.algorithm; +void main() +{ + foreach (varPair; environment.toAA().byKeyValue.array.sort!"a.key < b.key") + { + if (varPair.key != "_") + { + writeln(varPair.key, "=", varPair.value); + } + } +} diff --git a/test/runnable/sameenv.sh b/test/runnable/sameenv.sh new file mode 100644 index 00000000000..47680930035 --- /dev/null +++ b/test/runnable/sameenv.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +$DMD -m${MODEL} -of${OUTPUT_BASE}/printenv${EXE} ${EXTRA_FILES}/printenv.d +${OUTPUT_BASE}/printenv${EXE} > ${OUTPUT_BASE}/envFromExe.txt + +$DMD -m${MODEL} -run ${EXTRA_FILES}/printenv.d > ${OUTPUT_BASE}/envFromRun.txt + +diff -p ${OUTPUT_BASE}/envFromExe.txt ${OUTPUT_BASE}/envFromRun.txt + +rm -f ${OUTPUT_BASE}/*