Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(194)

Side by Side Diff: util/test/multiprocess_exec_win.cc

Issue 1051533002: test: Move util/test to its own top-level directory, test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Rebase Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 // Ref: http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/ everyone-quotes-arguments-the-wrong-way.aspx
27 void AppendCommandLineArgument(const std::wstring& argument,
28 std::wstring* command_line) {
29 // Don't bother quoting if unnecessary.
30 if (!argument.empty() &&
31 argument.find_first_of(L" \t\n\v\"") == std::wstring::npos) {
32 command_line->append(argument);
33 } else {
34 command_line->push_back(L'"');
35 for (std::wstring::const_iterator i = argument.begin();; ++i) {
36 size_t backslash_count = 0;
37 while (i != argument.end() && *i == L'\\') {
38 ++i;
39 ++backslash_count;
40 }
41 if (i == argument.end()) {
42 // Escape all backslashes, but let the terminating double quotation mark
43 // we add below be interpreted as a metacharacter.
44 command_line->append(backslash_count * 2, L'\\');
45 break;
46 } else if (*i == L'"') {
47 // Escape all backslashes and the following double quotation mark.
48 command_line->append(backslash_count * 2 + 1, L'\\');
49 command_line->push_back(*i);
50 } else {
51 // Backslashes aren't special here.
52 command_line->append(backslash_count, L'\\');
53 command_line->push_back(*i);
54 }
55 }
56 command_line->push_back(L'"');
57 }
58 }
59
60 } // namespace
61
62 namespace internal {
63
64 struct MultiprocessInfo {
65 MultiprocessInfo() {}
66 ScopedFileHANDLE pipe_c2p_read;
67 ScopedFileHANDLE pipe_c2p_write;
68 ScopedFileHANDLE pipe_p2c_read;
69 ScopedFileHANDLE pipe_p2c_write;
70 PROCESS_INFORMATION process_info;
71 };
72
73 } // namespace internal
74
75 Multiprocess::Multiprocess()
76 : info_(nullptr),
77 code_(EXIT_SUCCESS),
78 reason_(kTerminationNormal) {
79 }
80
81 void Multiprocess::Run() {
82 // Set up and spawn the child process.
83 ASSERT_NO_FATAL_FAILURE(PreFork());
84 RunChild();
85
86 // And then run the parent actions in this process.
87 RunParent();
88
89 // Reap the child.
90 WaitForSingleObject(info_->process_info.hProcess, INFINITE);
91 CloseHandle(info_->process_info.hThread);
92 CloseHandle(info_->process_info.hProcess);
93 }
94
95 Multiprocess::~Multiprocess() {
96 delete info_;
97 }
98
99 void Multiprocess::PreFork() {
100 NOTREACHED();
101 }
102
103 FileHandle Multiprocess::ReadPipeHandle() const {
104 // This is the parent case, it's stdin in the child.
105 return info_->pipe_c2p_read.get();
106 }
107
108 FileHandle Multiprocess::WritePipeHandle() const {
109 // This is the parent case, it's stdout in the child.
110 return info_->pipe_p2c_write.get();
111 }
112
113 void Multiprocess::CloseReadPipe() {
114 info_->pipe_c2p_read.reset();
115 }
116
117 void Multiprocess::CloseWritePipe() {
118 info_->pipe_p2c_write.reset();
119 }
120
121 void Multiprocess::RunParent() {
122 MultiprocessParent();
123
124 info_->pipe_c2p_read.reset();
125 info_->pipe_p2c_write.reset();
126 }
127
128 void Multiprocess::RunChild() {
129 MultiprocessChild();
130
131 info_->pipe_c2p_write.reset();
132 info_->pipe_p2c_read.reset();
133 }
134
135 MultiprocessExec::MultiprocessExec()
136 : Multiprocess(), command_(), arguments_(), command_line_() {
137 }
138
139 void MultiprocessExec::SetChildCommand(
140 const std::string& command,
141 const std::vector<std::string>* arguments) {
142 command_ = command;
143 if (arguments) {
144 arguments_ = *arguments;
145 } else {
146 arguments_.clear();
147 }
148 }
149
150 MultiprocessExec::~MultiprocessExec() {
151 }
152
153 void MultiprocessExec::PreFork() {
154 ASSERT_FALSE(command_.empty());
155
156 command_line_.clear();
157 AppendCommandLineArgument(base::UTF8ToUTF16(command_), &command_line_);
158 for (size_t i = 0; i < arguments_.size(); ++i) {
159 command_line_ += L" ";
160 AppendCommandLineArgument(base::UTF8ToUTF16(arguments_[i]), &command_line_);
161 }
162
163 // Make pipes for child-to-parent and parent-to-child communication. Mark them
164 // as inheritable via the SECURITY_ATTRIBUTES, but use SetHandleInformation to
165 // ensure that the parent sides are not inherited.
166 ASSERT_EQ(nullptr, info());
167 set_info(new internal::MultiprocessInfo());
168
169 SECURITY_ATTRIBUTES security_attributes = {0};
170 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
171 security_attributes.bInheritHandle = TRUE;
172
173 HANDLE c2p_read, c2p_write;
174 PCHECK(CreatePipe(&c2p_read, &c2p_write, &security_attributes, 0));
175 PCHECK(SetHandleInformation(c2p_read, HANDLE_FLAG_INHERIT, 0));
176 info()->pipe_c2p_read.reset(c2p_read);
177 info()->pipe_c2p_write.reset(c2p_write);
178
179 HANDLE p2c_read, p2c_write;
180 PCHECK(CreatePipe(&p2c_read, &p2c_write, &security_attributes, 0));
181 PCHECK(SetHandleInformation(p2c_write, HANDLE_FLAG_INHERIT, 0));
182 info()->pipe_p2c_read.reset(p2c_read);
183 info()->pipe_p2c_write.reset(p2c_write);
184 }
185
186 void MultiprocessExec::MultiprocessChild() {
187 STARTUPINFO startup_info = {0};
188 startup_info.cb = sizeof(startup_info);
189 startup_info.hStdInput = info()->pipe_p2c_read.get();
190 startup_info.hStdOutput = info()->pipe_c2p_write.get();
191 startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
192 startup_info.dwFlags = STARTF_USESTDHANDLES;
193 PCHECK(CreateProcess(base::UTF8ToUTF16(command_).c_str(),
194 &command_line_[0], // This cannot be constant, per MSDN.
195 nullptr,
196 nullptr,
197 TRUE,
198 0,
199 nullptr,
200 nullptr,
201 &startup_info,
202 &info()->process_info));
203 }
204
205 } // namespace test
206 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698