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

Side by Side Diff: util/win/exception_handler_server.cc

Issue 1432563003: win: crashpad_handler should create its own pipe name in ephemeral mode (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: It's futile to pick and choose errors, retry on all Created 5 years, 1 month 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
1 // Copyright 2015 The Crashpad Authors. All rights reserved. 1 // Copyright 2015 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 17 matching lines...) Expand all
28 #include "util/misc/tri_state.h" 28 #include "util/misc/tri_state.h"
29 #include "util/misc/uuid.h" 29 #include "util/misc/uuid.h"
30 #include "util/win/get_function.h" 30 #include "util/win/get_function.h"
31 #include "util/win/registration_protocol_win.h" 31 #include "util/win/registration_protocol_win.h"
32 #include "util/win/xp_compat.h" 32 #include "util/win/xp_compat.h"
33 33
34 namespace crashpad { 34 namespace crashpad {
35 35
36 namespace { 36 namespace {
37 37
38 // We create two pipe instances, so that there's one listening while the
39 // PipeServiceProc is processing a registration.
40 const size_t kPipeInstances = 2;
41
42 // Wraps CreateNamedPipe() to create a single named pipe instance.
43 //
44 // If first_instance is true, the named pipe instance will be created with
45 // FILE_FLAG_FIRST_PIPE_INSTANCE. This ensures that the the pipe name is not
46 // already in use when created.
47 HANDLE CreateNamedPipeInstance(const std::wstring& pipe_name,
48 bool first_instance) {
49 return CreateNamedPipe(pipe_name.c_str(),
50 PIPE_ACCESS_DUPLEX |
51 (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE
52 : 0),
53 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
54 kPipeInstances,
55 512,
56 512,
57 0,
58 nullptr);
59 }
60
38 decltype(GetNamedPipeClientProcessId)* GetNamedPipeClientProcessIdFunction() { 61 decltype(GetNamedPipeClientProcessId)* GetNamedPipeClientProcessIdFunction() {
39 static const auto get_named_pipe_client_process_id = 62 static const auto get_named_pipe_client_process_id =
40 GET_FUNCTION(L"kernel32.dll", ::GetNamedPipeClientProcessId); 63 GET_FUNCTION(L"kernel32.dll", ::GetNamedPipeClientProcessId);
41 return get_named_pipe_client_process_id; 64 return get_named_pipe_client_process_id;
42 } 65 }
43 66
44 HANDLE DuplicateEvent(HANDLE process, HANDLE event) { 67 HANDLE DuplicateEvent(HANDLE process, HANDLE event) {
45 HANDLE handle; 68 HANDLE handle;
46 if (DuplicateHandle(GetCurrentProcess(), 69 if (DuplicateHandle(GetCurrentProcess(),
47 event, 70 event,
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 WinVMAddress debug_critical_section_address_; 250 WinVMAddress debug_critical_section_address_;
228 251
229 DISALLOW_COPY_AND_ASSIGN(ClientData); 252 DISALLOW_COPY_AND_ASSIGN(ClientData);
230 }; 253 };
231 254
232 } // namespace internal 255 } // namespace internal
233 256
234 ExceptionHandlerServer::Delegate::~Delegate() { 257 ExceptionHandlerServer::Delegate::~Delegate() {
235 } 258 }
236 259
237 ExceptionHandlerServer::ExceptionHandlerServer(const std::string& pipe_name, 260 ExceptionHandlerServer::ExceptionHandlerServer(bool persistent)
238 bool persistent) 261 : pipe_name_(),
239 : pipe_name_(pipe_name),
240 port_(CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1)), 262 port_(CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1)),
263 first_pipe_instance_(),
241 clients_lock_(), 264 clients_lock_(),
242 clients_(), 265 clients_(),
243 persistent_(persistent) { 266 persistent_(persistent) {
244 } 267 }
245 268
246 ExceptionHandlerServer::~ExceptionHandlerServer() { 269 ExceptionHandlerServer::~ExceptionHandlerServer() {
247 } 270 }
248 271
272 void ExceptionHandlerServer::SetPipeName(const std::wstring& pipe_name) {
273 DCHECK(pipe_name_.empty());
274 DCHECK(!pipe_name.empty());
275
276 pipe_name_ = pipe_name;
277 }
278
279 std::wstring ExceptionHandlerServer::CreatePipe() {
280 DCHECK(pipe_name_.empty());
281 DCHECK(!first_pipe_instance_.is_valid());
282
283 int tries = 5;
284 std::string pipe_name_base =
285 base::StringPrintf("\\\\.\\pipe\\crashpad_%d_", GetCurrentProcessId());
286 std::wstring pipe_name;
287 do {
288 pipe_name = base::UTF8ToUTF16(pipe_name_base);
289 for (int index = 0; index < 16; ++index) {
290 pipe_name.append(1, static_cast<wchar_t>(base::RandInt('A', 'Z')));
291 }
292
293 first_pipe_instance_.reset(CreateNamedPipeInstance(pipe_name, true));
294
295 // CreateNamedPipe() is documented as setting the error to
296 // ERROR_ACCESS_DENIED if FILE_FLAG_FIRST_PIPE_INSTANCE is specified and the
297 // pipe name is already in use. However it may set the error to other codes
298 // such as ERROR_PIPE_BUSY (if the pipe already exists and has reached its
299 // maximum instance count) or ERROR_INVALID_PARAMETER (if the pipe already
300 // exists and its attributes differ from those specified to
301 // CreateNamedPipe()). Some of these errors may be ambiguous: for example,
302 // ERROR_INVALID_PARAMETER may also occur if CreateNamedPipe() is called
303 // incorrectly even in the absence of an existing pipe by the same name.
304 //
305 // Rather than chasing down all of the possible errors that might indicate
306 // that a pipe name is already in use, retry up to a few times on any error.
307 } while (!first_pipe_instance_.is_valid() && --tries);
308
309 PCHECK(first_pipe_instance_.is_valid()) << "CreateNamedPipe";
310
311 pipe_name_ = pipe_name;
scottmg 2015/11/03 20:52:07 Maybe call SetPipeName() here (and remove the firs
Mark Mentovai 2015/11/03 23:58:48 scottmg wrote:
312 return pipe_name_;
313 }
314
249 void ExceptionHandlerServer::Run(Delegate* delegate) { 315 void ExceptionHandlerServer::Run(Delegate* delegate) {
250 uint64_t shutdown_token = base::RandUint64(); 316 uint64_t shutdown_token = base::RandUint64();
251 // We create two pipe instances, so that there's one listening while the 317 ScopedKernelHANDLE thread_handles[kPipeInstances];
252 // PipeServiceProc is processing a registration.
253 ScopedKernelHANDLE thread_handles[2];
254 base::string16 pipe_name_16(base::UTF8ToUTF16(pipe_name_));
255 for (int i = 0; i < arraysize(thread_handles); ++i) { 318 for (int i = 0; i < arraysize(thread_handles); ++i) {
256 HANDLE pipe = 319 HANDLE pipe;
257 CreateNamedPipe(pipe_name_16.c_str(), 320 if (first_pipe_instance_.is_valid()) {
258 PIPE_ACCESS_DUPLEX, 321 pipe = first_pipe_instance_.release();
259 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 322 } else {
260 arraysize(thread_handles), 323 pipe = CreateNamedPipeInstance(pipe_name_, false);
261 512, 324 PCHECK(pipe != INVALID_HANDLE_VALUE) << "CreateNamedPipe";
262 512, 325 }
263 0,
264 nullptr);
265 PCHECK(pipe != INVALID_HANDLE_VALUE) << "CreateNamedPipe";
266 326
267 // Ownership of this object (and the pipe instance) is given to the new 327 // Ownership of this object (and the pipe instance) is given to the new
268 // thread. We close the thread handles at the end of the scope. They clean 328 // thread. We close the thread handles at the end of the scope. They clean
269 // up the context object and the pipe instance on termination. 329 // up the context object and the pipe instance on termination.
270 internal::PipeServiceContext* context = 330 internal::PipeServiceContext* context =
271 new internal::PipeServiceContext(port_.get(), 331 new internal::PipeServiceContext(port_.get(),
272 pipe, 332 pipe,
273 delegate, 333 delegate,
274 &clients_lock_, 334 &clients_lock_,
275 &clients_, 335 &clients_,
(...skipping 30 matching lines...) Expand all
306 break; 366 break;
307 } 367 }
308 368
309 // Signal to the named pipe instances that they should terminate. 369 // Signal to the named pipe instances that they should terminate.
310 for (int i = 0; i < arraysize(thread_handles); ++i) { 370 for (int i = 0; i < arraysize(thread_handles); ++i) {
311 ClientToServerMessage message; 371 ClientToServerMessage message;
312 memset(&message, 0, sizeof(message)); 372 memset(&message, 0, sizeof(message));
313 message.type = ClientToServerMessage::kShutdown; 373 message.type = ClientToServerMessage::kShutdown;
314 message.shutdown.token = shutdown_token; 374 message.shutdown.token = shutdown_token;
315 ServerToClientMessage response; 375 ServerToClientMessage response;
316 SendToCrashHandlerServer(pipe_name_16, 376 SendToCrashHandlerServer(pipe_name_,
317 reinterpret_cast<ClientToServerMessage&>(message), 377 reinterpret_cast<ClientToServerMessage&>(message),
318 &response); 378 &response);
319 } 379 }
320 380
321 for (auto& handle : thread_handles) 381 for (auto& handle : thread_handles)
322 WaitForSingleObject(handle.get(), INFINITE); 382 WaitForSingleObject(handle.get(), INFINITE);
323 383
324 // Deleting ClientData does a blocking wait until the threadpool executions 384 // Deleting ClientData does a blocking wait until the threadpool executions
325 // have terminated when unregistering them. 385 // have terminated when unregistering them.
326 { 386 {
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
501 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) { 561 void __stdcall ExceptionHandlerServer::OnProcessEnd(void* ctx, BOOLEAN) {
502 // This function is executed on the thread pool. 562 // This function is executed on the thread pool.
503 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx); 563 internal::ClientData* client = reinterpret_cast<internal::ClientData*>(ctx);
504 base::AutoLock lock(*client->lock()); 564 base::AutoLock lock(*client->lock());
505 565
506 // Post back to the main thread to have it delete this client record. 566 // Post back to the main thread to have it delete this client record.
507 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr); 567 PostQueuedCompletionStatus(client->port(), 0, ULONG_PTR(client), nullptr);
508 } 568 }
509 569
510 } // namespace crashpad 570 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698