Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 | |
| 15 #include "util/test/multiprocess_exec.h" | |
| 16 | |
| 17 #include "base/logging.h" | |
| 18 #include "base/strings/utf_string_conversions.h" | |
| 19 #include "gtest/gtest.h" | |
| 20 | |
| 21 namespace crashpad { | |
| 22 namespace test { | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 void ArgvQuote(const std::wstring& argument, std::wstring* command_line) { | |
|
Mark Mentovai
2015/01/28 19:58:28
It’s not obvious that this is additive. Add a comm
scottmg
2015/01/28 22:14:58
Done.
| |
| 27 // Don't bother quoting if unnecessary. | |
| 28 if (argument.empty() == false && | |
|
Mark Mentovai
2015/01/28 19:58:28
Adapt to local style: !argument.empty(), std::wstr
scottmg
2015/01/28 22:14:58
Done.
| |
| 29 argument.find_first_of(L" \t\n\v\"") == argument.npos) { | |
| 30 command_line->append(argument); | |
| 31 } else { | |
| 32 // Ref: http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04 /23/everyone-quotes-arguments-the-wrong-way.aspx | |
|
Mark Mentovai
2015/01/28 19:58:28
I’m glad you did this correctly. Sloppy quoting is
Mark Mentovai
2015/01/28 19:58:28
Promote this to the function-level comment?
scottmg
2015/01/28 22:14:58
Done.
| |
| 33 command_line->push_back(L'"'); | |
| 34 for (std::wstring::const_iterator i = argument.begin();; ++i) { | |
| 35 unsigned backslash_count = 0; | |
|
Mark Mentovai
2015/01/28 19:58:28
size_t
scottmg
2015/01/28 22:14:58
Done.
| |
| 36 while (i != argument.end() && *i == L'\\') { | |
| 37 ++i; | |
| 38 ++backslash_count; | |
| 39 } | |
| 40 if (i == argument.end()) { | |
| 41 // Escape all backslashes, but let the terminating double quotation mark | |
| 42 // we add below be interpreted as a metacharacter. | |
| 43 command_line->append(backslash_count * 2, L'\\'); | |
| 44 break; | |
| 45 } else if (*i == L'"') { | |
| 46 // Escape all backslashes and the following double quotation mark. | |
| 47 command_line->append(backslash_count * 2 + 1, L'\\'); | |
| 48 command_line->push_back(*i); | |
| 49 } else { | |
| 50 // Backslashes aren't special here. | |
| 51 command_line->append(backslash_count, L'\\'); | |
| 52 command_line->push_back(*i); | |
| 53 } | |
| 54 } | |
| 55 command_line->push_back(L'"'); | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 } // namespace | |
| 60 | |
| 61 namespace internal { | |
| 62 | |
| 63 struct MultiprocessInfo { | |
| 64 MultiprocessInfo() {} | |
| 65 ScopedFileHANDLE pipe_c2p_read; | |
| 66 ScopedFileHANDLE pipe_c2p_write; | |
| 67 ScopedFileHANDLE pipe_p2c_read; | |
| 68 ScopedFileHANDLE pipe_p2c_write; | |
| 69 PROCESS_INFORMATION process_info; | |
| 70 }; | |
| 71 | |
| 72 } // namespace internal | |
| 73 | |
| 74 Multiprocess::Multiprocess() | |
|
Mark Mentovai
2015/01/28 19:58:28
There should be a comment somewhere (maybe here, m
scottmg
2015/01/28 22:14:58
Done in header.
| |
| 75 : info_(nullptr), | |
| 76 code_(EXIT_SUCCESS), | |
| 77 reason_(kTerminationNormal) { | |
| 78 } | |
| 79 | |
| 80 void Multiprocess::Run() { | |
| 81 ASSERT_NO_FATAL_FAILURE(PreFork()); | |
| 82 RunChild(); | |
|
Mark Mentovai
2015/01/28 19:58:28
To that end, this whole function is kind of weird.
scottmg
2015/01/28 22:14:58
It's setting up and spawning the child, then runni
Mark Mentovai
2015/01/28 22:32:54
scottmg wrote:
| |
| 83 RunParent(); | |
| 84 | |
| 85 // Reap the child. | |
| 86 WaitForSingleObject(info_->process_info.hProcess, INFINITE); | |
| 87 CloseHandle(info_->process_info.hThread); | |
| 88 CloseHandle(info_->process_info.hProcess); | |
| 89 } | |
| 90 | |
| 91 Multiprocess::~Multiprocess() { | |
| 92 delete info_; | |
| 93 } | |
| 94 | |
| 95 void Multiprocess::PreFork() { | |
| 96 NOTREACHED(); | |
| 97 } | |
| 98 | |
| 99 FileHandle Multiprocess::ReadPipeHandle() const { | |
| 100 // This is the parent case, it's stdin in the child. | |
| 101 return info_->pipe_c2p_read.get(); | |
| 102 } | |
| 103 | |
| 104 FileHandle Multiprocess::WritePipeHandle() const { | |
| 105 // This is the parent case, it's stdout in the child. | |
| 106 return info_->pipe_p2c_write.get(); | |
| 107 } | |
| 108 | |
|
Mark Mentovai
2015/01/28 19:58:28
You haven’t implemented ChildPID() (but you probab
scottmg
2015/01/28 22:14:58
Done.
| |
| 109 void Multiprocess::RunParent() { | |
| 110 MultiprocessParent(); | |
| 111 | |
| 112 info_->pipe_c2p_read.reset(); | |
| 113 info_->pipe_p2c_write.reset(); | |
| 114 } | |
| 115 | |
| 116 void Multiprocess::RunChild() { | |
| 117 MultiprocessChild(); | |
| 118 | |
| 119 info_->pipe_c2p_write.reset(); | |
| 120 info_->pipe_p2c_read.reset(); | |
| 121 } | |
| 122 | |
| 123 MultiprocessExec::MultiprocessExec() | |
| 124 : Multiprocess(), command_(), arguments_(), argv_() { | |
| 125 } | |
| 126 | |
| 127 void MultiprocessExec::SetChildCommand( | |
| 128 const std::string& command, | |
| 129 const std::vector<std::string>* arguments) { | |
| 130 command_ = command; | |
| 131 if (arguments) { | |
| 132 arguments_ = *arguments; | |
| 133 } else { | |
| 134 arguments_.clear(); | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 MultiprocessExec::~MultiprocessExec() { | |
| 139 } | |
| 140 | |
| 141 void MultiprocessExec::PreFork() { | |
| 142 ASSERT_FALSE(command_.empty()); | |
| 143 | |
| 144 argv_.clear(); | |
| 145 ArgvQuote(base::UTF8ToUTF16(command_), &argv_); | |
| 146 for (size_t i = 0; i < arguments_.size(); ++i) { | |
| 147 argv_ += L" "; | |
| 148 ArgvQuote(base::UTF8ToUTF16(arguments_[i]), &argv_); | |
| 149 } | |
| 150 | |
| 151 // Make pipes for child-to-parent and parent-to-child communication. Mark them | |
| 152 // as inheritable via the SECURITY_ATTRIBUTES, but use SetHandleInformation to | |
| 153 // ensure that the parent sides are not inherited. | |
| 154 ASSERT_EQ(nullptr, info()); | |
| 155 set_info(new internal::MultiprocessInfo); | |
|
Mark Mentovai
2015/01/28 19:58:28
() to be explicit.
scottmg
2015/01/28 22:14:58
Done.
| |
| 156 | |
| 157 SECURITY_ATTRIBUTES security_attributes = {0}; | |
| 158 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); | |
| 159 security_attributes.bInheritHandle = TRUE; | |
| 160 | |
| 161 HANDLE c2p_read, c2p_write; | |
| 162 PCHECK(CreatePipe(&c2p_read, &c2p_write, &security_attributes, 0)); | |
| 163 PCHECK(SetHandleInformation(c2p_read, HANDLE_FLAG_INHERIT, 0)); | |
| 164 info()->pipe_c2p_read.reset(c2p_read); | |
| 165 info()->pipe_c2p_write.reset(c2p_write); | |
| 166 | |
| 167 HANDLE p2c_read, p2c_write; | |
| 168 PCHECK(CreatePipe(&p2c_read, &p2c_write, &security_attributes, 0)); | |
| 169 PCHECK(SetHandleInformation(p2c_write, HANDLE_FLAG_INHERIT, 0)); | |
| 170 info()->pipe_p2c_read.reset(p2c_read); | |
| 171 info()->pipe_p2c_write.reset(p2c_write); | |
| 172 } | |
| 173 | |
| 174 void MultiprocessExec::MultiprocessChild() { | |
| 175 STARTUPINFO startup_info = {0}; | |
| 176 startup_info.cb = sizeof(startup_info); | |
| 177 startup_info.hStdInput = info()->pipe_p2c_read.get(); | |
| 178 startup_info.hStdOutput = info()->pipe_c2p_write.get(); | |
| 179 startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); | |
| 180 startup_info.dwFlags = STARTF_USESTDHANDLES; | |
| 181 PCHECK(CreateProcess(base::UTF8ToUTF16(command_).c_str(), | |
| 182 &argv_[0], // This cannot be constant, per MSDN. | |
| 183 nullptr, | |
| 184 nullptr, | |
| 185 TRUE, | |
| 186 0, | |
| 187 nullptr, | |
| 188 nullptr, | |
| 189 &startup_info, | |
| 190 &info()->process_info)); | |
| 191 } | |
| 192 | |
| 193 } // namespace test | |
| 194 } // namespace crashpad | |
| OLD | NEW |