OLD | NEW |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 const base::FilePath& handler, | 90 const base::FilePath& handler, |
91 const base::FilePath& database, | 91 const base::FilePath& database, |
92 const std::string& url, | 92 const std::string& url, |
93 const std::map<std::string, std::string>& annotations, | 93 const std::map<std::string, std::string>& annotations, |
94 const std::vector<std::string>& arguments) { | 94 const std::vector<std::string>& arguments) { |
95 DCHECK(!exception_port_.is_valid()); | 95 DCHECK(!exception_port_.is_valid()); |
96 | 96 |
97 // Set up the arguments for execve() first. These aren’t needed until execve() | 97 // Set up the arguments for execve() first. These aren’t needed until execve() |
98 // is called, but it’s dangerous to do this in a child process after fork(). | 98 // is called, but it’s dangerous to do this in a child process after fork(). |
99 ChildPortHandshake child_port_handshake; | 99 ChildPortHandshake child_port_handshake; |
100 int handshake_fd = child_port_handshake.ReadPipeFD(); | 100 base::ScopedFD client_read_fd = child_port_handshake.ClientReadFD(); |
101 | 101 |
102 // Use handler as argv[0], followed by arguments directed by this method’s | 102 // Use handler as argv[0], followed by arguments directed by this method’s |
103 // parameters and a --handshake-fd argument. |arguments| are added first so | 103 // parameters and a --handshake-fd argument. |arguments| are added first so |
104 // that if it erroneously contains an argument such as --url, the actual |url| | 104 // that if it erroneously contains an argument such as --url, the actual |url| |
105 // argument passed to this method will supersede it. In normal command-line | 105 // argument passed to this method will supersede it. In normal command-line |
106 // processing, the last parameter wins in the case of a conflict. | 106 // processing, the last parameter wins in the case of a conflict. |
107 std::vector<std::string> argv(1, handler.value()); | 107 std::vector<std::string> argv(1, handler.value()); |
108 argv.reserve(1 + arguments.size() + 2 + annotations.size() + 1); | 108 argv.reserve(1 + arguments.size() + 2 + annotations.size() + 1); |
109 for (const std::string& argument : arguments) { | 109 for (const std::string& argument : arguments) { |
110 argv.push_back(argument); | 110 argv.push_back(argument); |
111 } | 111 } |
112 if (!database.value().empty()) { | 112 if (!database.value().empty()) { |
113 argv.push_back(FormatArgumentString("database", database.value())); | 113 argv.push_back(FormatArgumentString("database", database.value())); |
114 } | 114 } |
115 if (!url.empty()) { | 115 if (!url.empty()) { |
116 argv.push_back(FormatArgumentString("url", url)); | 116 argv.push_back(FormatArgumentString("url", url)); |
117 } | 117 } |
118 for (const auto& kv : annotations) { | 118 for (const auto& kv : annotations) { |
119 argv.push_back( | 119 argv.push_back( |
120 FormatArgumentString("annotation", kv.first + '=' + kv.second)); | 120 FormatArgumentString("annotation", kv.first + '=' + kv.second)); |
121 } | 121 } |
122 argv.push_back(FormatArgumentInt("handshake-fd", handshake_fd)); | 122 argv.push_back(FormatArgumentInt("handshake-fd", client_read_fd.get())); |
123 | 123 |
124 // argv_c contains const char* pointers and is terminated by nullptr. argv | 124 // argv_c contains const char* pointers and is terminated by nullptr. argv |
125 // is required because the pointers in argv_c need to point somewhere, and | 125 // is required because the pointers in argv_c need to point somewhere, and |
126 // they can’t point to temporaries such as those returned by | 126 // they can’t point to temporaries such as those returned by |
127 // FormatArgumentString(). | 127 // FormatArgumentString(). |
128 std::vector<const char*> argv_c; | 128 std::vector<const char*> argv_c; |
129 argv_c.reserve(argv.size() + 1); | 129 argv_c.reserve(argv.size() + 1); |
130 for (const std::string& argument : argv) { | 130 for (const std::string& argument : argv) { |
131 argv_c.push_back(argument.c_str()); | 131 argv_c.push_back(argument.c_str()); |
132 } | 132 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 | 174 |
175 if (pid > 0) { | 175 if (pid > 0) { |
176 // Child process. | 176 // Child process. |
177 | 177 |
178 // _exit() instead of exit(), because fork() was called. | 178 // _exit() instead of exit(), because fork() was called. |
179 _exit(EXIT_SUCCESS); | 179 _exit(EXIT_SUCCESS); |
180 } | 180 } |
181 | 181 |
182 // Grandchild process. | 182 // Grandchild process. |
183 | 183 |
184 CloseMultipleNowOrOnExec(STDERR_FILENO + 1, handshake_fd); | 184 CloseMultipleNowOrOnExec(STDERR_FILENO + 1, client_read_fd.get()); |
185 | 185 |
186 // &argv_c[0] is a pointer to a pointer to const char data, but because of | 186 // &argv_c[0] is a pointer to a pointer to const char data, but because of |
187 // how C (not C++) works, execvp() wants a pointer to a const pointer to | 187 // how C (not C++) works, execvp() wants a pointer to a const pointer to |
188 // char data. It modifies neither the data nor the pointers, so the | 188 // char data. It modifies neither the data nor the pointers, so the |
189 // const_cast is safe. | 189 // const_cast is safe. |
190 execvp(handler.value().c_str(), const_cast<char* const*>(&argv_c[0])); | 190 execvp(handler.value().c_str(), const_cast<char* const*>(&argv_c[0])); |
191 PLOG(FATAL) << "execvp " << handler.value(); | 191 PLOG(FATAL) << "execvp " << handler.value(); |
192 } | 192 } |
193 | 193 |
194 // Parent process. | 194 // Parent process. |
195 | 195 |
| 196 client_read_fd.reset(); |
| 197 |
196 // waitpid() for the child, so that it does not become a zombie process. The | 198 // waitpid() for the child, so that it does not become a zombie process. The |
197 // child normally exits quickly. | 199 // child normally exits quickly. |
198 int status; | 200 int status; |
199 pid_t wait_pid = HANDLE_EINTR(waitpid(pid, &status, 0)); | 201 pid_t wait_pid = HANDLE_EINTR(waitpid(pid, &status, 0)); |
200 PCHECK(wait_pid != -1) << "waitpid"; | 202 PCHECK(wait_pid != -1) << "waitpid"; |
201 DCHECK_EQ(wait_pid, pid); | 203 DCHECK_EQ(wait_pid, pid); |
202 | 204 |
203 if (WIFSIGNALED(status)) { | 205 if (WIFSIGNALED(status)) { |
204 LOG(WARNING) << "intermediate process: signal " << WTERMSIG(status); | 206 LOG(WARNING) << "intermediate process: signal " << WTERMSIG(status); |
205 } else if (!WIFEXITED(status)) { | 207 } else if (!WIFEXITED(status)) { |
206 DLOG(WARNING) << "intermediate process: unknown termination " << status; | 208 DLOG(WARNING) << "intermediate process: unknown termination " << status; |
207 } else if (WEXITSTATUS(status) != EXIT_SUCCESS) { | 209 } else if (WEXITSTATUS(status) != EXIT_SUCCESS) { |
208 LOG(WARNING) << "intermediate process: exit status " << WEXITSTATUS(status); | 210 LOG(WARNING) << "intermediate process: exit status " << WEXITSTATUS(status); |
209 } | 211 } |
210 | 212 |
211 // Rendezvous with the handler running in the grandchild process. | 213 // Rendezvous with the handler running in the grandchild process. |
212 exception_port_.reset(child_port_handshake.RunServer()); | 214 exception_port_.reset(child_port_handshake.RunServer( |
| 215 ChildPortHandshake::PortRightType::kSendRight)); |
213 | 216 |
214 return exception_port_.is_valid(); | 217 return exception_port_.is_valid(); |
215 } | 218 } |
216 | 219 |
217 bool CrashpadClient::UseHandler() { | 220 bool CrashpadClient::UseHandler() { |
218 DCHECK(exception_port_.is_valid()); | 221 DCHECK(exception_port_.is_valid()); |
219 | 222 |
220 return SetCrashExceptionPorts(exception_port_.get()); | 223 return SetCrashExceptionPorts(exception_port_.get()); |
221 } | 224 } |
222 | 225 |
223 // static | 226 // static |
224 void CrashpadClient::UseSystemDefaultHandler() { | 227 void CrashpadClient::UseSystemDefaultHandler() { |
225 base::mac::ScopedMachSendRight | 228 base::mac::ScopedMachSendRight |
226 system_crash_reporter_handler(SystemCrashReporterHandler()); | 229 system_crash_reporter_handler(SystemCrashReporterHandler()); |
227 | 230 |
228 // Proceed even if SystemCrashReporterHandler() failed, setting MACH_PORT_NULL | 231 // Proceed even if SystemCrashReporterHandler() failed, setting MACH_PORT_NULL |
229 // to clear the current exception ports. | 232 // to clear the current exception ports. |
230 if (!SetCrashExceptionPorts(system_crash_reporter_handler.get())) { | 233 if (!SetCrashExceptionPorts(system_crash_reporter_handler.get())) { |
231 SetCrashExceptionPorts(MACH_PORT_NULL); | 234 SetCrashExceptionPorts(MACH_PORT_NULL); |
232 } | 235 } |
233 } | 236 } |
234 | 237 |
235 } // namespace crashpad | 238 } // namespace crashpad |
OLD | NEW |