| Index: client/crashpad_client_mac.cc
|
| diff --git a/client/crashpad_client_mac.cc b/client/crashpad_client_mac.cc
|
| index 2858ac4802a704269bdaeb86fedeb3f5e354e21a..2ac274d0f00cadeb2294e6e70baacff90df1dd24 100644
|
| --- a/client/crashpad_client_mac.cc
|
| +++ b/client/crashpad_client_mac.cc
|
| @@ -27,6 +27,19 @@
|
| #include "util/mach/mach_extensions.h"
|
| #include "util/posix/close_multiple.h"
|
|
|
| +namespace {
|
| +
|
| +std::string FormatArgumentString(const std::string& name,
|
| + const std::string& value) {
|
| + return base::StringPrintf("--%s=%s", name.c_str(), value.c_str());
|
| +}
|
| +
|
| +std::string FormatArgumentInt(const std::string& name, int value) {
|
| + return base::StringPrintf("--%s=%d", name.c_str(), value);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| namespace crashpad {
|
|
|
| CrashpadClient::CrashpadClient()
|
| @@ -38,28 +51,49 @@ CrashpadClient::~CrashpadClient() {
|
|
|
| bool CrashpadClient::StartHandler(
|
| const base::FilePath& handler,
|
| - const std::vector<std::string>& handler_arguments) {
|
| + const base::FilePath& database,
|
| + const std::string& url,
|
| + const std::map<std::string, std::string>& annotations,
|
| + const std::vector<std::string>& arguments) {
|
| DCHECK_EQ(exception_port_, kMachPortNull);
|
|
|
| // Set up the arguments for execve() first. These aren’t needed until execve()
|
| // is called, but it’s dangerous to do this in a child process after fork().
|
| ChildPortHandshake child_port_handshake;
|
| int handshake_fd = child_port_handshake.ReadPipeFD();
|
| - std::string handshake_fd_arg =
|
| - base::StringPrintf("--handshake-fd=%d", handshake_fd);
|
| -
|
| - const std::string& handler_s = handler.value();
|
| - const char* const handler_c = handler_s.c_str();
|
| -
|
| - // Use handler as argv[0], followed by handler_arguments, handshake_fd_arg,
|
| - // and a nullptr terminator.
|
| - std::vector<const char*> argv(1, handler_c);
|
| - argv.reserve(1 + handler_arguments.size() + 1 + 1);
|
| - for (const std::string& handler_argument : handler_arguments) {
|
| - argv.push_back(handler_argument.c_str());
|
| +
|
| + // Use handler as argv[0], followed by arguments directed by this method’s
|
| + // parameters and a --handshake-fd argument. |arguments| are added first so
|
| + // that if it erroneously contains an argument such as --url, the actual |url|
|
| + // argument passed to this method will supersede it. In normal command-line
|
| + // processing, the last parameter wins in the case of a conflict.
|
| + std::vector<std::string> argv(1, handler.value());
|
| + argv.reserve(1 + arguments.size() + 2 + annotations.size() + 1);
|
| + for (const std::string& argument : arguments) {
|
| + argv.push_back(argument);
|
| + }
|
| + if (!database.value().empty()) {
|
| + argv.push_back(FormatArgumentString("database", database.value()));
|
| + }
|
| + if (!url.empty()) {
|
| + argv.push_back(FormatArgumentString("url", url));
|
| + }
|
| + for (const auto& kv : annotations) {
|
| + argv.push_back(
|
| + FormatArgumentString("annotation", kv.first + '=' + kv.second));
|
| + }
|
| + argv.push_back(FormatArgumentInt("handshake-fd", handshake_fd));
|
| +
|
| + // argv_c contains const char* pointers and is terminated by nullptr. argv
|
| + // is required because the pointers in argv_c need to point somewhere, and
|
| + // they can’t point to temporaries such as those returned by
|
| + // FormatArgumentString().
|
| + std::vector<const char*> argv_c;
|
| + argv_c.reserve(argv.size() + 1);
|
| + for (const std::string& argument : argv) {
|
| + argv_c.push_back(argument.c_str());
|
| }
|
| - argv.push_back(handshake_fd_arg.c_str());
|
| - argv.push_back(nullptr);
|
| + argv_c.push_back(nullptr);
|
|
|
| // Double-fork(). The three processes involved are parent, child, and
|
| // grandchild. The grandchild will become the handler process. The child exits
|
| @@ -112,12 +146,12 @@ bool CrashpadClient::StartHandler(
|
|
|
| CloseMultipleNowOrOnExec(STDERR_FILENO + 1, handshake_fd);
|
|
|
| - // &argv[0] is a pointer to a pointer to const char data, but because of how
|
| - // C (not C++) works, execvp() wants a pointer to a const pointer to char
|
| - // data. It modifies neither the data nor the pointers, so the const_cast is
|
| - // safe.
|
| - execvp(handler_c, const_cast<char* const*>(&argv[0]));
|
| - PLOG(FATAL) << "execvp " << handler_s;
|
| + // &argv_c[0] is a pointer to a pointer to const char data, but because of
|
| + // how C (not C++) works, execvp() wants a pointer to a const pointer to
|
| + // char data. It modifies neither the data nor the pointers, so the
|
| + // const_cast is safe.
|
| + execvp(handler.value().c_str(), const_cast<char* const*>(&argv_c[0]));
|
| + PLOG(FATAL) << "execvp " << handler.value();
|
| }
|
|
|
| // Parent process.
|
|
|