From 0b675d88309bdcbb387bbee907c4ef9d98e412a2 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Mon, 22 Apr 2013 19:03:55 +0000 Subject: [Support] Fix argv string escape bug on Windows Summary: This is http://llvm.org/PR15802. Backslashes preceding double quotes in arguments must be escaped. The interesting bit is that all other backslashes should *not* be escaped, because the un-escaping logic is only triggered by the presence of a double quote character. Reviewers: Bigcheese CC: llvm-commits Differential Revision: http://llvm-reviews.chandlerc.com/D705 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180035 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/Support/ProgramTest.cpp | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100755 unittests/Support/ProgramTest.cpp (limited to 'unittests/Support/ProgramTest.cpp') diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp new file mode 100755 index 0000000000..03083aa68b --- /dev/null +++ b/unittests/Support/ProgramTest.cpp @@ -0,0 +1,63 @@ +//===- unittest/Support/ProgramTest.cpp -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "gtest/gtest.h" + +#include + +namespace { + +using namespace llvm; +using namespace sys; + +static cl::opt +ProgramTestStringArg1("program-test-string-arg1"); +static cl::opt +ProgramTestStringArg2("program-test-string-arg2"); + +TEST(ProgramTest, CreateProcessTrailingSlash) { + if (getenv("LLVM_PROGRAM_TEST_CHILD")) { + if (ProgramTestStringArg1 == "has\\\\ trailing\\" && + ProgramTestStringArg2 == "has\\\\ trailing\\") { + exit(0); // Success! The arguments were passed and parsed. + } + exit(1); + } + + // FIXME: Hardcoding argv0 here since I don't know a good cross-platform way + // to get it. Maybe ParseCommandLineOptions() should save it? + Path my_exe = Path::GetMainExecutable("SupportTests", &ProgramTestStringArg1); + const char *argv[] = { + my_exe.c_str(), + "--gtest_filter=ProgramTest.CreateProcessTrailingSlashChild", + "-program-test-string-arg1", "has\\\\ trailing\\", + "-program-test-string-arg2", "has\\\\ trailing\\", + 0 + }; + const char *envp[] = { "LLVM_PROGRAM_TEST_CHILD=1", 0 }; + std::string error; + bool ExecutionFailed; + // Redirect stdout and stdin to NUL, but let stderr through. +#ifdef LLVM_ON_WIN32 + Path nul("NUL"); +#else + Path nul("/dev/null"); +#endif + const Path *redirects[] = { &nul, &nul, 0 }; + int rc = Program::ExecuteAndWait(my_exe, argv, envp, redirects, + /*secondsToWait=*/10, /*memoryLimit=*/0, + &error, &ExecutionFailed); + EXPECT_FALSE(ExecutionFailed) << error; + EXPECT_EQ(0, rc); +} + +} // end anonymous namespace -- cgit v1.2.3-70-g09d2 From 6641fa7c6c8873343d94f48a996209ebeb7b5b34 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Mon, 22 Apr 2013 20:23:41 +0000 Subject: [Support] Propagate the environment into the test child process Should fix the dragonegg bootstrap builder, which reasonably needs LD_LIBRARY_PATH to be set. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180041 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/Support/ProgramTest.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'unittests/Support/ProgramTest.cpp') diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp index 03083aa68b..479b6b57ec 100755 --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -24,6 +24,15 @@ ProgramTestStringArg1("program-test-string-arg1"); static cl::opt ProgramTestStringArg2("program-test-string-arg2"); +static void CopyEnvironment(std::vector out) { + // environ appears to be pretty portable. + char **envp = environ; + while (*envp != 0) { + out.push_back(*envp); + ++envp; + } +} + TEST(ProgramTest, CreateProcessTrailingSlash) { if (getenv("LLVM_PROGRAM_TEST_CHILD")) { if (ProgramTestStringArg1 == "has\\\\ trailing\\" && @@ -43,7 +52,13 @@ TEST(ProgramTest, CreateProcessTrailingSlash) { "-program-test-string-arg2", "has\\\\ trailing\\", 0 }; - const char *envp[] = { "LLVM_PROGRAM_TEST_CHILD=1", 0 }; + + // Add LLVM_PROGRAM_TEST_CHILD to the environment of the child. + std::vector envp; + CopyEnvironment(envp); + envp.push_back("LLVM_PROGRAM_TEST_CHILD=1"); + envp.push_back(0); + std::string error; bool ExecutionFailed; // Redirect stdout and stdin to NUL, but let stderr through. @@ -53,7 +68,7 @@ TEST(ProgramTest, CreateProcessTrailingSlash) { Path nul("/dev/null"); #endif const Path *redirects[] = { &nul, &nul, 0 }; - int rc = Program::ExecuteAndWait(my_exe, argv, envp, redirects, + int rc = Program::ExecuteAndWait(my_exe, argv, &envp[0], redirects, /*secondsToWait=*/10, /*memoryLimit=*/0, &error, &ExecutionFailed); EXPECT_FALSE(ExecutionFailed) << error; -- cgit v1.2.3-70-g09d2 From 0af5493701f9982d7451c8b3c1b7699cc84ac94c Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Mon, 22 Apr 2013 20:58:09 +0000 Subject: Add a missing reference on a std::vector<> out param Pointed out by Eli. The test passes for me either way, so I missed this. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180046 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/Support/ProgramTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'unittests/Support/ProgramTest.cpp') diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp index 479b6b57ec..9dd9ccd11b 100755 --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -24,7 +24,7 @@ ProgramTestStringArg1("program-test-string-arg1"); static cl::opt ProgramTestStringArg2("program-test-string-arg2"); -static void CopyEnvironment(std::vector out) { +static void CopyEnvironment(std::vector &out) { // environ appears to be pretty portable. char **envp = environ; while (*envp != 0) { -- cgit v1.2.3-70-g09d2 From 2c8dc64357083e81b36a44698a4bacb229f12317 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Mon, 22 Apr 2013 22:51:55 +0000 Subject: Revert "Add a missing reference on a std::vector<> out param" Revert "[Support] Propagate the environment into the test child process" This reverts commit r180046. This reverts commit r180041. These have broken buildbots for ~3 hours: http://lab.llvm.org:8013/builders/clang-x86_64-darwin11-nobootstrap-RAincremental/builds/763 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180066 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/Support/ProgramTest.cpp | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'unittests/Support/ProgramTest.cpp') diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp index 9dd9ccd11b..03083aa68b 100755 --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -24,15 +24,6 @@ ProgramTestStringArg1("program-test-string-arg1"); static cl::opt ProgramTestStringArg2("program-test-string-arg2"); -static void CopyEnvironment(std::vector &out) { - // environ appears to be pretty portable. - char **envp = environ; - while (*envp != 0) { - out.push_back(*envp); - ++envp; - } -} - TEST(ProgramTest, CreateProcessTrailingSlash) { if (getenv("LLVM_PROGRAM_TEST_CHILD")) { if (ProgramTestStringArg1 == "has\\\\ trailing\\" && @@ -52,13 +43,7 @@ TEST(ProgramTest, CreateProcessTrailingSlash) { "-program-test-string-arg2", "has\\\\ trailing\\", 0 }; - - // Add LLVM_PROGRAM_TEST_CHILD to the environment of the child. - std::vector envp; - CopyEnvironment(envp); - envp.push_back("LLVM_PROGRAM_TEST_CHILD=1"); - envp.push_back(0); - + const char *envp[] = { "LLVM_PROGRAM_TEST_CHILD=1", 0 }; std::string error; bool ExecutionFailed; // Redirect stdout and stdin to NUL, but let stderr through. @@ -68,7 +53,7 @@ TEST(ProgramTest, CreateProcessTrailingSlash) { Path nul("/dev/null"); #endif const Path *redirects[] = { &nul, &nul, 0 }; - int rc = Program::ExecuteAndWait(my_exe, argv, &envp[0], redirects, + int rc = Program::ExecuteAndWait(my_exe, argv, envp, redirects, /*secondsToWait=*/10, /*memoryLimit=*/0, &error, &ExecutionFailed); EXPECT_FALSE(ExecutionFailed) << error; -- cgit v1.2.3-70-g09d2 From 8eca677afee90d6a28487fd3db0bca129bde7186 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 23 Apr 2013 13:15:51 +0000 Subject: Un-revert the environ copy in ProgramTest after fixing it on OS X This was r180041 and r180046, which was reverted in r180066. Re-committing this should fix the dragonegg bootstrap, which I presume needs LD_LIBRARY_PATH to be propagated to the child. Tested on Linux, Windows, and Mac OS 10.6. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180099 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/Support/ProgramTest.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'unittests/Support/ProgramTest.cpp') diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp index 03083aa68b..80b0334c67 100755 --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -13,6 +13,12 @@ #include "gtest/gtest.h" #include +#ifdef __APPLE__ +# include +#else +// Forward declare environ in case it's not provided by stdlib.h. +extern char **environ; +#endif namespace { @@ -24,6 +30,21 @@ ProgramTestStringArg1("program-test-string-arg1"); static cl::opt ProgramTestStringArg2("program-test-string-arg2"); +static void CopyEnvironment(std::vector &out) { +#ifdef __APPLE__ + // _NSGetEnviron() only works from the main exe on Mac. Fortunately the test + // should be in the executable. + char **envp = *_NSGetEnviron(); +#else + // environ seems to work for Windows and most other Unices. + char **envp = environ; +#endif + while (*envp != 0) { + out.push_back(*envp); + ++envp; + } +} + TEST(ProgramTest, CreateProcessTrailingSlash) { if (getenv("LLVM_PROGRAM_TEST_CHILD")) { if (ProgramTestStringArg1 == "has\\\\ trailing\\" && @@ -43,7 +64,13 @@ TEST(ProgramTest, CreateProcessTrailingSlash) { "-program-test-string-arg2", "has\\\\ trailing\\", 0 }; - const char *envp[] = { "LLVM_PROGRAM_TEST_CHILD=1", 0 }; + + // Add LLVM_PROGRAM_TEST_CHILD to the environment of the child. + std::vector envp; + CopyEnvironment(envp); + envp.push_back("LLVM_PROGRAM_TEST_CHILD=1"); + envp.push_back(0); + std::string error; bool ExecutionFailed; // Redirect stdout and stdin to NUL, but let stderr through. @@ -53,7 +80,7 @@ TEST(ProgramTest, CreateProcessTrailingSlash) { Path nul("/dev/null"); #endif const Path *redirects[] = { &nul, &nul, 0 }; - int rc = Program::ExecuteAndWait(my_exe, argv, envp, redirects, + int rc = Program::ExecuteAndWait(my_exe, argv, &envp[0], redirects, /*secondsToWait=*/10, /*memoryLimit=*/0, &error, &ExecutionFailed); EXPECT_FALSE(ExecutionFailed) << error; -- cgit v1.2.3-70-g09d2 From 268adf2a03cf352593b632c5249c83f4fc56956f Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 24 Apr 2013 17:50:30 +0000 Subject: Don't forward declare environ on Windows That seems to interact poorly with the environ and _environ macros defined in MSVC's . Also remove the incorrect comment about _NSGetEnviron(). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180200 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/Support/ProgramTest.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'unittests/Support/ProgramTest.cpp') diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp index 80b0334c67..279e2e8d0f 100755 --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -13,9 +13,9 @@ #include "gtest/gtest.h" #include -#ifdef __APPLE__ +#if defined(__APPLE__) # include -#else +#elif !defined(_MSC_VER) // Forward declare environ in case it's not provided by stdlib.h. extern char **environ; #endif @@ -32,8 +32,6 @@ ProgramTestStringArg2("program-test-string-arg2"); static void CopyEnvironment(std::vector &out) { #ifdef __APPLE__ - // _NSGetEnviron() only works from the main exe on Mac. Fortunately the test - // should be in the executable. char **envp = *_NSGetEnviron(); #else // environ seems to work for Windows and most other Unices. -- cgit v1.2.3-70-g09d2 From 2a839438559bc7d3067ff2166105f47e0af06b37 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 30 Apr 2013 04:30:41 +0000 Subject: Try to fix ProgramTest on FreeBSD This seemed like the cleanest way to find the test executable. Also fix the file mode. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180770 91177308-0d34-0410-b5e6-96231b3b80d8 --- unittests/Support/ProgramTest.cpp | 7 ++++--- utils/unittest/UnitTestMain/TestMain.cpp | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) mode change 100755 => 100644 unittests/Support/ProgramTest.cpp (limited to 'unittests/Support/ProgramTest.cpp') diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp old mode 100755 new mode 100644 index 279e2e8d0f..6cbb05454f --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -20,6 +20,9 @@ extern char **environ; #endif +// From TestMain.cpp. +extern const char *TestMainArgv0; + namespace { using namespace llvm; @@ -52,9 +55,7 @@ TEST(ProgramTest, CreateProcessTrailingSlash) { exit(1); } - // FIXME: Hardcoding argv0 here since I don't know a good cross-platform way - // to get it. Maybe ParseCommandLineOptions() should save it? - Path my_exe = Path::GetMainExecutable("SupportTests", &ProgramTestStringArg1); + Path my_exe = Path::GetMainExecutable(TestMainArgv0, &ProgramTestStringArg1); const char *argv[] = { my_exe.c_str(), "--gtest_filter=ProgramTest.CreateProcessTrailingSlashChild", diff --git a/utils/unittest/UnitTestMain/TestMain.cpp b/utils/unittest/UnitTestMain/TestMain.cpp index ce32b7380f..5387512e6f 100644 --- a/utils/unittest/UnitTestMain/TestMain.cpp +++ b/utils/unittest/UnitTestMain/TestMain.cpp @@ -20,11 +20,16 @@ # endif #endif +const char *TestMainArgv0; + int main(int argc, char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); testing::InitGoogleTest(&argc, argv); llvm::cl::ParseCommandLineOptions(argc, argv); + // Make it easy for a test to re-execute itself by saving argv[0]. + TestMainArgv0 = argv[0]; + # if defined(LLVM_ON_WIN32) // Disable all of the possible ways Windows conspires to make automated // testing impossible. -- cgit v1.2.3-70-g09d2