| 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 |