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