xref: /aosp_15_r20/external/google-breakpad/src/client/windows/handler/exception_handler.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2006 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>  // Must come first
31 #endif
32 
33 #include <objbase.h>
34 
35 #include <algorithm>
36 #include <cassert>
37 #include <cstdio>
38 
39 #include "common/windows/string_utils-inl.h"
40 
41 #include "client/windows/common/ipc_protocol.h"
42 #include "client/windows/handler/exception_handler.h"
43 #include "common/windows/guid_string.h"
44 
45 namespace google_breakpad {
46 
47 // This is passed as the context to the MinidumpWriteDump callback.
48 typedef struct {
49   AppMemoryList::const_iterator iter;
50   AppMemoryList::const_iterator end;
51 } MinidumpCallbackContext;
52 
53 // This define is new to Windows 10.
54 #ifndef DBG_PRINTEXCEPTION_WIDE_C
55 #define DBG_PRINTEXCEPTION_WIDE_C ((DWORD)0x4001000A)
56 #endif
57 
58 vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
59 LONG ExceptionHandler::handler_stack_index_ = 0;
60 CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_;
61 volatile LONG ExceptionHandler::instance_count_ = 0;
62 
ExceptionHandler(const wstring & dump_path,FilterCallback filter,MinidumpCallback callback,void * callback_context,int handler_types,MINIDUMP_TYPE dump_type,const wchar_t * pipe_name,const CustomClientInfo * custom_info)63 ExceptionHandler::ExceptionHandler(const wstring& dump_path,
64                                    FilterCallback filter,
65                                    MinidumpCallback callback,
66                                    void* callback_context,
67                                    int handler_types,
68                                    MINIDUMP_TYPE dump_type,
69                                    const wchar_t* pipe_name,
70                                    const CustomClientInfo* custom_info) {
71   Initialize(dump_path,
72              filter,
73              callback,
74              callback_context,
75              handler_types,
76              dump_type,
77              pipe_name,
78              NULL,  // pipe_handle
79              NULL,  // crash_generation_client
80              custom_info);
81 }
82 
ExceptionHandler(const wstring & dump_path,FilterCallback filter,MinidumpCallback callback,void * callback_context,int handler_types,MINIDUMP_TYPE dump_type,HANDLE pipe_handle,const CustomClientInfo * custom_info)83 ExceptionHandler::ExceptionHandler(const wstring& dump_path,
84                                    FilterCallback filter,
85                                    MinidumpCallback callback,
86                                    void* callback_context,
87                                    int handler_types,
88                                    MINIDUMP_TYPE dump_type,
89                                    HANDLE pipe_handle,
90                                    const CustomClientInfo* custom_info) {
91   Initialize(dump_path,
92              filter,
93              callback,
94              callback_context,
95              handler_types,
96              dump_type,
97              NULL,  // pipe_name
98              pipe_handle,
99              NULL,  // crash_generation_client
100              custom_info);
101 }
102 
ExceptionHandler(const wstring & dump_path,FilterCallback filter,MinidumpCallback callback,void * callback_context,int handler_types,CrashGenerationClient * crash_generation_client)103 ExceptionHandler::ExceptionHandler(
104     const wstring& dump_path,
105     FilterCallback filter,
106     MinidumpCallback callback,
107     void* callback_context,
108     int handler_types,
109     CrashGenerationClient* crash_generation_client) {
110   // The dump_type, pipe_name and custom_info that are passed in to Initialize()
111   // are not used.  The ones set in crash_generation_client are used instead.
112   Initialize(dump_path,
113              filter,
114              callback,
115              callback_context,
116              handler_types,
117              MiniDumpNormal,           // dump_type - not used
118              NULL,                     // pipe_name - not used
119              NULL,                     // pipe_handle
120              crash_generation_client,
121              NULL);                    // custom_info - not used
122 }
123 
ExceptionHandler(const wstring & dump_path,FilterCallback filter,MinidumpCallback callback,void * callback_context,int handler_types)124 ExceptionHandler::ExceptionHandler(const wstring& dump_path,
125                                    FilterCallback filter,
126                                    MinidumpCallback callback,
127                                    void* callback_context,
128                                    int handler_types) {
129   Initialize(dump_path,
130              filter,
131              callback,
132              callback_context,
133              handler_types,
134              MiniDumpNormal,
135              NULL,   // pipe_name
136              NULL,   // pipe_handle
137              NULL,   // crash_generation_client
138              NULL);  // custom_info
139 }
140 
Initialize(const wstring & dump_path,FilterCallback filter,MinidumpCallback callback,void * callback_context,int handler_types,MINIDUMP_TYPE dump_type,const wchar_t * pipe_name,HANDLE pipe_handle,CrashGenerationClient * crash_generation_client,const CustomClientInfo * custom_info)141 void ExceptionHandler::Initialize(
142     const wstring& dump_path,
143     FilterCallback filter,
144     MinidumpCallback callback,
145     void* callback_context,
146     int handler_types,
147     MINIDUMP_TYPE dump_type,
148     const wchar_t* pipe_name,
149     HANDLE pipe_handle,
150     CrashGenerationClient* crash_generation_client,
151     const CustomClientInfo* custom_info) {
152   LONG instance_count = InterlockedIncrement(&instance_count_);
153   filter_ = filter;
154   callback_ = callback;
155   callback_context_ = callback_context;
156   dump_path_c_ = NULL;
157   next_minidump_id_c_ = NULL;
158   next_minidump_path_c_ = NULL;
159   dbghelp_module_ = NULL;
160   minidump_write_dump_ = NULL;
161   dump_type_ = dump_type;
162   rpcrt4_module_ = NULL;
163   uuid_create_ = NULL;
164   handler_types_ = handler_types;
165   previous_filter_ = NULL;
166 #if _MSC_VER >= 1400  // MSVC 2005/8
167   previous_iph_ = NULL;
168 #endif  // _MSC_VER >= 1400
169   previous_pch_ = NULL;
170   handler_thread_ = NULL;
171   is_shutdown_ = false;
172   handler_start_semaphore_ = NULL;
173   handler_finish_semaphore_ = NULL;
174   requesting_thread_id_ = 0;
175   exception_info_ = NULL;
176   assertion_ = NULL;
177   handler_return_value_ = false;
178   handle_debug_exceptions_ = false;
179   consume_invalid_handle_exceptions_ = false;
180 
181   // Attempt to use out-of-process if user has specified a pipe or a
182   // crash generation client.
183   scoped_ptr<CrashGenerationClient> client;
184   if (crash_generation_client) {
185     client.reset(crash_generation_client);
186   } else if (pipe_name) {
187     client.reset(
188       new CrashGenerationClient(pipe_name, dump_type_, custom_info));
189   } else if (pipe_handle) {
190     client.reset(
191       new CrashGenerationClient(pipe_handle, dump_type_, custom_info));
192   }
193 
194   if (client.get() != NULL) {
195     // If successful in registering with the monitoring process,
196     // there is no need to setup in-process crash generation.
197     if (client->Register()) {
198       crash_generation_client_.reset(client.release());
199     }
200   }
201 
202   if (!IsOutOfProcess()) {
203     // Either client did not ask for out-of-process crash generation
204     // or registration with the server process failed. In either case,
205     // setup to do in-process crash generation.
206 
207     // Set synchronization primitives and the handler thread.  Each
208     // ExceptionHandler object gets its own handler thread because that's the
209     // only way to reliably guarantee sufficient stack space in an exception,
210     // and it allows an easy way to get a snapshot of the requesting thread's
211     // context outside of an exception.
212     InitializeCriticalSection(&handler_critical_section_);
213     handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
214     assert(handler_start_semaphore_ != NULL);
215 
216     handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
217     assert(handler_finish_semaphore_ != NULL);
218 
219     // Don't attempt to create the thread if we could not create the semaphores.
220     if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) {
221       DWORD thread_id;
222       const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
223       handler_thread_ = CreateThread(NULL,         // lpThreadAttributes
224                                      kExceptionHandlerThreadInitialStackSize,
225                                      ExceptionHandlerThreadMain,
226                                      this,         // lpParameter
227                                      0,            // dwCreationFlags
228                                      &thread_id);
229       assert(handler_thread_ != NULL);
230     }
231 
232     dbghelp_module_ = LoadLibrary(L"dbghelp.dll");
233     if (dbghelp_module_) {
234       minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>(
235           GetProcAddress(dbghelp_module_, "MiniDumpWriteDump"));
236     }
237 
238     // Load this library dynamically to not affect existing projects.  Most
239     // projects don't link against this directly, it's usually dynamically
240     // loaded by dependent code.
241     rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll");
242     if (rpcrt4_module_) {
243       uuid_create_ = reinterpret_cast<UuidCreate_type>(
244           GetProcAddress(rpcrt4_module_, "UuidCreate"));
245     }
246 
247     // set_dump_path calls UpdateNextID.  This sets up all of the path and id
248     // strings, and their equivalent c_str pointers.
249     set_dump_path(dump_path);
250   }
251 
252   // Reserve one element for the instruction memory
253   AppMemory instruction_memory;
254   instruction_memory.ptr = NULL;
255   instruction_memory.length = 0;
256   app_memory_info_.push_back(instruction_memory);
257 
258   // There is a race condition here. If the first instance has not yet
259   // initialized the critical section, the second (and later) instances may
260   // try to use uninitialized critical section object. The feature of multiple
261   // instances in one module is not used much, so leave it as is for now.
262   // One way to solve this in the current design (that is, keeping the static
263   // handler stack) is to use spin locks with volatile bools to synchronize
264   // the handler stack. This works only if the compiler guarantees to generate
265   // cache coherent code for volatile.
266   // TODO(munjal): Fix this in a better way by changing the design if possible.
267 
268   // Lazy initialization of the handler_stack_critical_section_
269   if (instance_count == 1) {
270     InitializeCriticalSection(&handler_stack_critical_section_);
271   }
272 
273   if (handler_types != HANDLER_NONE) {
274     EnterCriticalSection(&handler_stack_critical_section_);
275 
276     // The first time an ExceptionHandler that installs a handler is
277     // created, set up the handler stack.
278     if (!handler_stack_) {
279       handler_stack_ = new vector<ExceptionHandler*>();
280     }
281     handler_stack_->push_back(this);
282 
283     if (handler_types & HANDLER_EXCEPTION)
284       previous_filter_ = SetUnhandledExceptionFilter(HandleException);
285 
286 #if _MSC_VER >= 1400  // MSVC 2005/8
287     if (handler_types & HANDLER_INVALID_PARAMETER)
288       previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter);
289 #endif  // _MSC_VER >= 1400
290 
291     if (handler_types & HANDLER_PURECALL)
292       previous_pch_ = _set_purecall_handler(HandlePureVirtualCall);
293 
294     LeaveCriticalSection(&handler_stack_critical_section_);
295   }
296 }
297 
~ExceptionHandler()298 ExceptionHandler::~ExceptionHandler() {
299   if (dbghelp_module_) {
300     FreeLibrary(dbghelp_module_);
301   }
302 
303   if (rpcrt4_module_) {
304     FreeLibrary(rpcrt4_module_);
305   }
306 
307   if (handler_types_ != HANDLER_NONE) {
308     EnterCriticalSection(&handler_stack_critical_section_);
309 
310     if (handler_types_ & HANDLER_EXCEPTION)
311       SetUnhandledExceptionFilter(previous_filter_);
312 
313 #if _MSC_VER >= 1400  // MSVC 2005/8
314     if (handler_types_ & HANDLER_INVALID_PARAMETER)
315       _set_invalid_parameter_handler(previous_iph_);
316 #endif  // _MSC_VER >= 1400
317 
318     if (handler_types_ & HANDLER_PURECALL)
319       _set_purecall_handler(previous_pch_);
320 
321     if (handler_stack_->back() == this) {
322       handler_stack_->pop_back();
323     } else {
324       // TODO(mmentovai): use advapi32!ReportEvent to log the warning to the
325       // system's application event log.
326       fprintf(stderr, "warning: removing Breakpad handler out of order\n");
327       vector<ExceptionHandler*>::iterator iterator = handler_stack_->begin();
328       while (iterator != handler_stack_->end()) {
329         if (*iterator == this) {
330           iterator = handler_stack_->erase(iterator);
331         } else {
332           ++iterator;
333         }
334       }
335     }
336 
337     if (handler_stack_->empty()) {
338       // When destroying the last ExceptionHandler that installed a handler,
339       // clean up the handler stack.
340       delete handler_stack_;
341       handler_stack_ = NULL;
342     }
343 
344     LeaveCriticalSection(&handler_stack_critical_section_);
345   }
346 
347   // Some of the objects were only initialized if out of process
348   // registration was not done.
349   if (!IsOutOfProcess()) {
350 #ifdef BREAKPAD_NO_TERMINATE_THREAD
351     // Clean up the handler thread and synchronization primitives. The handler
352     // thread is either waiting on the semaphore to handle a crash or it is
353     // handling a crash. Coming out of the wait is fast but wait more in the
354     // eventuality a crash is handled.  This compilation option results in a
355     // deadlock if the exception handler is destroyed while executing code
356     // inside DllMain.
357     is_shutdown_ = true;
358     ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
359     const int kWaitForHandlerThreadMs = 60000;
360     WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs);
361 #else
362     TerminateThread(handler_thread_, 1);
363 #endif  // BREAKPAD_NO_TERMINATE_THREAD
364 
365     CloseHandle(handler_thread_);
366     handler_thread_ = NULL;
367     DeleteCriticalSection(&handler_critical_section_);
368     CloseHandle(handler_start_semaphore_);
369     CloseHandle(handler_finish_semaphore_);
370   }
371 
372   // There is a race condition in the code below: if this instance is
373   // deleting the static critical section and a new instance of the class
374   // is created, then there is a possibility that the critical section be
375   // initialized while the same critical section is being deleted. Given the
376   // usage pattern for the code, this race condition is unlikely to hit, but it
377   // is a race condition nonetheless.
378   if (InterlockedDecrement(&instance_count_) == 0) {
379     DeleteCriticalSection(&handler_stack_critical_section_);
380   }
381 }
382 
RequestUpload(DWORD crash_id)383 bool ExceptionHandler::RequestUpload(DWORD crash_id) {
384   return crash_generation_client_->RequestUpload(crash_id);
385 }
386 
387 // static
ExceptionHandlerThreadMain(void * lpParameter)388 DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) {
389   ExceptionHandler* self = reinterpret_cast<ExceptionHandler*>(lpParameter);
390   assert(self);
391   assert(self->handler_start_semaphore_ != NULL);
392   assert(self->handler_finish_semaphore_ != NULL);
393 
394   for (;;) {
395     if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) ==
396         WAIT_OBJECT_0) {
397       // Perform the requested action.
398       if (self->is_shutdown_) {
399         // The instance of the exception handler is being destroyed.
400         break;
401       } else {
402         self->handler_return_value_ =
403             self->WriteMinidumpWithException(self->requesting_thread_id_,
404                                              self->exception_info_,
405                                              self->assertion_);
406       }
407 
408       // Allow the requesting thread to proceed.
409       ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL);
410     }
411   }
412 
413   // This statement is not reached when the thread is unconditionally
414   // terminated by the ExceptionHandler destructor.
415   return 0;
416 }
417 
418 // HandleException and HandleInvalidParameter must create an
419 // AutoExceptionHandler object to maintain static state and to determine which
420 // ExceptionHandler instance to use.  The constructor locates the correct
421 // instance, and makes it available through get_handler().  The destructor
422 // restores the state in effect prior to allocating the AutoExceptionHandler.
423 class AutoExceptionHandler {
424  public:
AutoExceptionHandler()425   AutoExceptionHandler() {
426     // Increment handler_stack_index_ so that if another Breakpad handler is
427     // registered using this same HandleException function, and it needs to be
428     // called while this handler is running (either because this handler
429     // declines to handle the exception, or an exception occurs during
430     // handling), HandleException will find the appropriate ExceptionHandler
431     // object in handler_stack_ to deliver the exception to.
432     //
433     // Because handler_stack_ is addressed in reverse (as |size - index|),
434     // preincrementing handler_stack_index_ avoids needing to subtract 1 from
435     // the argument to |at|.
436     //
437     // The index is maintained instead of popping elements off of the handler
438     // stack and pushing them at the end of this method.  This avoids ruining
439     // the order of elements in the stack in the event that some other thread
440     // decides to manipulate the handler stack (such as creating a new
441     // ExceptionHandler object) while an exception is being handled.
442     EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
443     handler_ = ExceptionHandler::handler_stack_->at(
444         ExceptionHandler::handler_stack_->size() -
445         ++ExceptionHandler::handler_stack_index_);
446 
447     // In case another exception occurs while this handler is doing its thing,
448     // it should be delivered to the previous filter.
449     SetUnhandledExceptionFilter(handler_->previous_filter_);
450 #if _MSC_VER >= 1400  // MSVC 2005/8
451     _set_invalid_parameter_handler(handler_->previous_iph_);
452 #endif  // _MSC_VER >= 1400
453     _set_purecall_handler(handler_->previous_pch_);
454   }
455 
~AutoExceptionHandler()456   ~AutoExceptionHandler() {
457     // Put things back the way they were before entering this handler.
458     SetUnhandledExceptionFilter(ExceptionHandler::HandleException);
459 #if _MSC_VER >= 1400  // MSVC 2005/8
460     _set_invalid_parameter_handler(ExceptionHandler::HandleInvalidParameter);
461 #endif  // _MSC_VER >= 1400
462     _set_purecall_handler(ExceptionHandler::HandlePureVirtualCall);
463 
464     --ExceptionHandler::handler_stack_index_;
465     LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
466   }
467 
get_handler() const468   ExceptionHandler* get_handler() const { return handler_; }
469 
470  private:
471   ExceptionHandler* handler_;
472 };
473 
474 // static
HandleException(EXCEPTION_POINTERS * exinfo)475 LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) {
476   AutoExceptionHandler auto_exception_handler;
477   ExceptionHandler* current_handler = auto_exception_handler.get_handler();
478 
479   // Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions.  This
480   // logic will short-circuit before calling WriteMinidumpOnHandlerThread,
481   // allowing something else to handle the breakpoint without incurring the
482   // overhead transitioning to and from the handler thread.  This behavior
483   // can be overridden by calling ExceptionHandler::set_handle_debug_exceptions.
484   DWORD code = exinfo->ExceptionRecord->ExceptionCode;
485   LONG action;
486   bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) ||
487                             (code == EXCEPTION_SINGLE_STEP) ||
488                             (code == DBG_PRINTEXCEPTION_C) ||
489                             (code == DBG_PRINTEXCEPTION_WIDE_C);
490 
491   if (code == EXCEPTION_INVALID_HANDLE &&
492       current_handler->consume_invalid_handle_exceptions_) {
493     return EXCEPTION_CONTINUE_EXECUTION;
494   }
495 
496   bool success = false;
497 
498   if (!is_debug_exception ||
499       current_handler->get_handle_debug_exceptions()) {
500     // If out-of-proc crash handler client is available, we have to use that
501     // to generate dump and we cannot fall back on in-proc dump generation
502     // because we never prepared for an in-proc dump generation
503 
504     // In case of out-of-process dump generation, directly call
505     // WriteMinidumpWithException since there is no separate thread running.
506     if (current_handler->IsOutOfProcess()) {
507       success = current_handler->WriteMinidumpWithException(
508           GetCurrentThreadId(),
509           exinfo,
510           NULL);
511     } else {
512       success = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL);
513     }
514   }
515 
516   // The handler fully handled the exception.  Returning
517   // EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually
518   // results in the application being terminated.
519   //
520   // Note: If the application was launched from within the Cygwin
521   // environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the
522   // application to be restarted.
523   if (success) {
524     action = EXCEPTION_EXECUTE_HANDLER;
525   } else {
526     // There was an exception, it was a breakpoint or something else ignored
527     // above, or it was passed to the handler, which decided not to handle it.
528     // This could be because the filter callback didn't want it, because
529     // minidump writing failed for some reason, or because the post-minidump
530     // callback function indicated failure.  Give the previous handler a
531     // chance to do something with the exception.  If there is no previous
532     // handler, return EXCEPTION_CONTINUE_SEARCH, which will allow a debugger
533     // or native "crashed" dialog to handle the exception.
534     if (current_handler->previous_filter_) {
535       action = current_handler->previous_filter_(exinfo);
536     } else {
537       action = EXCEPTION_CONTINUE_SEARCH;
538     }
539   }
540 
541   return action;
542 }
543 
544 #if _MSC_VER >= 1400  // MSVC 2005/8
545 // static
HandleInvalidParameter(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t reserved)546 void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression,
547                                               const wchar_t* function,
548                                               const wchar_t* file,
549                                               unsigned int line,
550                                               uintptr_t reserved) {
551   // This is an invalid parameter, not an exception.  It's safe to play with
552   // sprintf here.
553   AutoExceptionHandler auto_exception_handler;
554   ExceptionHandler* current_handler = auto_exception_handler.get_handler();
555 
556   MDRawAssertionInfo assertion;
557   memset(&assertion, 0, sizeof(assertion));
558   _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.expression),
559                sizeof(assertion.expression) / sizeof(assertion.expression[0]),
560                _TRUNCATE, L"%s", expression);
561   _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.function),
562                sizeof(assertion.function) / sizeof(assertion.function[0]),
563                _TRUNCATE, L"%s", function);
564   _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.file),
565                sizeof(assertion.file) / sizeof(assertion.file[0]),
566                _TRUNCATE, L"%s", file);
567   assertion.line = line;
568   assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER;
569 
570   // Make up an exception record for the current thread and CPU context
571   // to make it possible for the crash processor to classify these
572   // as do regular crashes, and to make it humane for developers to
573   // analyze them.
574   EXCEPTION_RECORD exception_record = {};
575   CONTEXT exception_context = {};
576   EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };
577 
578   ::RtlCaptureContext(&exception_context);
579 
580   exception_record.ExceptionCode = STATUS_INVALID_PARAMETER;
581 
582   // We store pointers to the the expression and function strings,
583   // and the line as exception parameters to make them easy to
584   // access by the developer on the far side.
585   exception_record.NumberParameters = 3;
586   exception_record.ExceptionInformation[0] =
587       reinterpret_cast<ULONG_PTR>(&assertion.expression);
588   exception_record.ExceptionInformation[1] =
589       reinterpret_cast<ULONG_PTR>(&assertion.file);
590   exception_record.ExceptionInformation[2] = assertion.line;
591 
592   bool success = false;
593   // In case of out-of-process dump generation, directly call
594   // WriteMinidumpWithException since there is no separate thread running.
595   if (current_handler->IsOutOfProcess()) {
596     success = current_handler->WriteMinidumpWithException(
597         GetCurrentThreadId(),
598         &exception_ptrs,
599         &assertion);
600   } else {
601     success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs,
602                                                             &assertion);
603   }
604 
605   if (!success) {
606     if (current_handler->previous_iph_) {
607       // The handler didn't fully handle the exception.  Give it to the
608       // previous invalid parameter handler.
609       current_handler->previous_iph_(expression,
610                                      function,
611                                      file,
612                                      line,
613                                      reserved);
614     } else {
615       // If there's no previous handler, pass the exception back in to the
616       // invalid parameter handler's core.  That's the routine that called this
617       // function, but now, since this function is no longer registered (and in
618       // fact, no function at all is registered), this will result in the
619       // default code path being taken: _CRT_DEBUGGER_HOOK and _invoke_watson.
620       // Use _invalid_parameter where it exists (in _DEBUG builds) as it passes
621       // more information through.  In non-debug builds, it is not available,
622       // so fall back to using _invalid_parameter_noinfo.  See invarg.c in the
623       // CRT source.
624 #ifdef _DEBUG
625       _invalid_parameter(expression, function, file, line, reserved);
626 #else  // _DEBUG
627       _invalid_parameter_noinfo();
628 #endif  // _DEBUG
629     }
630   }
631 
632   // The handler either took care of the invalid parameter problem itself,
633   // or passed it on to another handler.  "Swallow" it by exiting, paralleling
634   // the behavior of "swallowing" exceptions.
635   exit(0);
636 }
637 #endif  // _MSC_VER >= 1400
638 
639 // static
HandlePureVirtualCall()640 void ExceptionHandler::HandlePureVirtualCall() {
641   // This is an pure virtual function call, not an exception.  It's safe to
642   // play with sprintf here.
643   AutoExceptionHandler auto_exception_handler;
644   ExceptionHandler* current_handler = auto_exception_handler.get_handler();
645 
646   MDRawAssertionInfo assertion;
647   memset(&assertion, 0, sizeof(assertion));
648   assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL;
649 
650   // Make up an exception record for the current thread and CPU context
651   // to make it possible for the crash processor to classify these
652   // as do regular crashes, and to make it humane for developers to
653   // analyze them.
654   EXCEPTION_RECORD exception_record = {};
655   CONTEXT exception_context = {};
656   EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };
657 
658   ::RtlCaptureContext(&exception_context);
659 
660   exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
661 
662   // We store pointers to the the expression and function strings,
663   // and the line as exception parameters to make them easy to
664   // access by the developer on the far side.
665   exception_record.NumberParameters = 3;
666   exception_record.ExceptionInformation[0] =
667       reinterpret_cast<ULONG_PTR>(&assertion.expression);
668   exception_record.ExceptionInformation[1] =
669       reinterpret_cast<ULONG_PTR>(&assertion.file);
670   exception_record.ExceptionInformation[2] = assertion.line;
671 
672   bool success = false;
673   // In case of out-of-process dump generation, directly call
674   // WriteMinidumpWithException since there is no separate thread running.
675 
676   if (current_handler->IsOutOfProcess()) {
677     success = current_handler->WriteMinidumpWithException(
678         GetCurrentThreadId(),
679         &exception_ptrs,
680         &assertion);
681   } else {
682     success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs,
683                                                             &assertion);
684   }
685 
686   if (!success) {
687     if (current_handler->previous_pch_) {
688       // The handler didn't fully handle the exception.  Give it to the
689       // previous purecall handler.
690       current_handler->previous_pch_();
691     } else {
692       // If there's no previous handler, return and let _purecall handle it.
693       // This will just put up an assertion dialog.
694       return;
695     }
696   }
697 
698   // The handler either took care of the invalid parameter problem itself,
699   // or passed it on to another handler.  "Swallow" it by exiting, paralleling
700   // the behavior of "swallowing" exceptions.
701   exit(0);
702 }
703 
WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS * exinfo,MDRawAssertionInfo * assertion)704 bool ExceptionHandler::WriteMinidumpOnHandlerThread(
705     EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) {
706   EnterCriticalSection(&handler_critical_section_);
707 
708   // There isn't much we can do if the handler thread
709   // was not successfully created.
710   if (handler_thread_ == NULL) {
711     LeaveCriticalSection(&handler_critical_section_);
712     return false;
713   }
714 
715   // The handler thread should only be created when the semaphores are valid.
716   assert(handler_start_semaphore_ != NULL);
717   assert(handler_finish_semaphore_ != NULL);
718 
719   // Set up data to be passed in to the handler thread.
720   requesting_thread_id_ = GetCurrentThreadId();
721   exception_info_ = exinfo;
722   assertion_ = assertion;
723 
724   // This causes the handler thread to call WriteMinidumpWithException.
725   ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
726 
727   // Wait until WriteMinidumpWithException is done and collect its return value.
728   WaitForSingleObject(handler_finish_semaphore_, INFINITE);
729   bool status = handler_return_value_;
730 
731   // Clean up.
732   requesting_thread_id_ = 0;
733   exception_info_ = NULL;
734   assertion_ = NULL;
735 
736   LeaveCriticalSection(&handler_critical_section_);
737 
738   return status;
739 }
740 
WriteMinidump()741 bool ExceptionHandler::WriteMinidump() {
742   // Make up an exception record for the current thread and CPU context
743   // to make it possible for the crash processor to classify these
744   // as do regular crashes, and to make it humane for developers to
745   // analyze them.
746   EXCEPTION_RECORD exception_record = {};
747   CONTEXT exception_context = {};
748   EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };
749 
750   ::RtlCaptureContext(&exception_context);
751   exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
752 
753   return WriteMinidumpForException(&exception_ptrs);
754 }
755 
WriteMinidumpForException(EXCEPTION_POINTERS * exinfo)756 bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) {
757   // In case of out-of-process dump generation, directly call
758   // WriteMinidumpWithException since there is no separate thread running.
759   if (IsOutOfProcess()) {
760     return WriteMinidumpWithException(GetCurrentThreadId(),
761                                       exinfo,
762                                       NULL);
763   }
764 
765   bool success = WriteMinidumpOnHandlerThread(exinfo, NULL);
766   UpdateNextID();
767   return success;
768 }
769 
770 // static
WriteMinidump(const wstring & dump_path,MinidumpCallback callback,void * callback_context,MINIDUMP_TYPE dump_type)771 bool ExceptionHandler::WriteMinidump(const wstring& dump_path,
772                                      MinidumpCallback callback,
773                                      void* callback_context,
774                                      MINIDUMP_TYPE dump_type) {
775   ExceptionHandler handler(dump_path, NULL, callback, callback_context,
776                            HANDLER_NONE, dump_type, (HANDLE)NULL, NULL);
777   return handler.WriteMinidump();
778 }
779 
780 // static
WriteMinidumpForChild(HANDLE child,DWORD child_blamed_thread,const wstring & dump_path,MinidumpCallback callback,void * callback_context,MINIDUMP_TYPE dump_type)781 bool ExceptionHandler::WriteMinidumpForChild(HANDLE child,
782                                              DWORD child_blamed_thread,
783                                              const wstring& dump_path,
784                                              MinidumpCallback callback,
785                                              void* callback_context,
786                                              MINIDUMP_TYPE dump_type) {
787   EXCEPTION_RECORD ex;
788   CONTEXT ctx;
789   EXCEPTION_POINTERS exinfo = { NULL, NULL };
790   // As documented on MSDN, on failure SuspendThread returns (DWORD) -1
791   const DWORD kFailedToSuspendThread = static_cast<DWORD>(-1);
792   DWORD last_suspend_count = kFailedToSuspendThread;
793   HANDLE child_thread_handle = OpenThread(THREAD_GET_CONTEXT |
794                                           THREAD_QUERY_INFORMATION |
795                                           THREAD_SUSPEND_RESUME,
796                                           FALSE,
797                                           child_blamed_thread);
798   // This thread may have died already, so not opening the handle is a
799   // non-fatal error.
800   if (child_thread_handle != NULL) {
801     last_suspend_count = SuspendThread(child_thread_handle);
802     if (last_suspend_count != kFailedToSuspendThread) {
803       ctx.ContextFlags = CONTEXT_ALL;
804       if (GetThreadContext(child_thread_handle, &ctx)) {
805         memset(&ex, 0, sizeof(ex));
806         ex.ExceptionCode = EXCEPTION_BREAKPOINT;
807 #if defined(_M_IX86)
808         ex.ExceptionAddress = reinterpret_cast<PVOID>(ctx.Eip);
809 #elif defined(_M_X64)
810         ex.ExceptionAddress = reinterpret_cast<PVOID>(ctx.Rip);
811 #endif
812         exinfo.ExceptionRecord = &ex;
813         exinfo.ContextRecord = &ctx;
814       }
815     }
816   }
817 
818   ExceptionHandler handler(dump_path, NULL, callback, callback_context,
819                            HANDLER_NONE, dump_type, (HANDLE)NULL, NULL);
820   bool success = handler.WriteMinidumpWithExceptionForProcess(
821       child_blamed_thread,
822       exinfo.ExceptionRecord ? &exinfo : NULL,
823       NULL, child, false);
824 
825   if (last_suspend_count != kFailedToSuspendThread) {
826     ResumeThread(child_thread_handle);
827   }
828 
829   CloseHandle(child_thread_handle);
830 
831   if (callback) {
832     success = callback(handler.dump_path_c_, handler.next_minidump_id_c_,
833                        callback_context, NULL, NULL, success);
834   }
835 
836   return success;
837 }
838 
WriteMinidumpWithException(DWORD requesting_thread_id,EXCEPTION_POINTERS * exinfo,MDRawAssertionInfo * assertion)839 bool ExceptionHandler::WriteMinidumpWithException(
840     DWORD requesting_thread_id,
841     EXCEPTION_POINTERS* exinfo,
842     MDRawAssertionInfo* assertion) {
843   // Give user code a chance to approve or prevent writing a minidump.  If the
844   // filter returns false, don't handle the exception at all.  If this method
845   // was called as a result of an exception, returning false will cause
846   // HandleException to call any previous handler or return
847   // EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear
848   // as though this handler were not present at all.
849   if (filter_ && !filter_(callback_context_, exinfo, assertion)) {
850     return false;
851   }
852 
853   bool success = false;
854   if (IsOutOfProcess()) {
855     success = crash_generation_client_->RequestDump(exinfo, assertion);
856   } else {
857     success = WriteMinidumpWithExceptionForProcess(requesting_thread_id,
858                                                    exinfo,
859                                                    assertion,
860                                                    GetCurrentProcess(),
861                                                    true);
862   }
863 
864   if (callback_) {
865     // TODO(munjal): In case of out-of-process dump generation, both
866     // dump_path_c_ and next_minidump_id_ will be NULL. For out-of-process
867     // scenario, the server process ends up creating the dump path and dump
868     // id so they are not known to the client.
869     success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
870                         exinfo, assertion, success);
871   }
872 
873   return success;
874 }
875 
876 // static
MinidumpWriteDumpCallback(PVOID context,const PMINIDUMP_CALLBACK_INPUT callback_input,PMINIDUMP_CALLBACK_OUTPUT callback_output)877 BOOL CALLBACK ExceptionHandler::MinidumpWriteDumpCallback(
878     PVOID context,
879     const PMINIDUMP_CALLBACK_INPUT callback_input,
880     PMINIDUMP_CALLBACK_OUTPUT callback_output) {
881   switch (callback_input->CallbackType) {
882   case MemoryCallback: {
883     MinidumpCallbackContext* callback_context =
884         reinterpret_cast<MinidumpCallbackContext*>(context);
885     if (callback_context->iter == callback_context->end)
886       return FALSE;
887 
888     // Include the specified memory region.
889     callback_output->MemoryBase = callback_context->iter->ptr;
890     callback_output->MemorySize = callback_context->iter->length;
891     callback_context->iter++;
892     return TRUE;
893   }
894 
895     // Include all modules.
896   case IncludeModuleCallback:
897   case ModuleCallback:
898     return TRUE;
899 
900     // Include all threads.
901   case IncludeThreadCallback:
902   case ThreadCallback:
903     return TRUE;
904 
905     // Stop receiving cancel callbacks.
906   case CancelCallback:
907     callback_output->CheckCancel = FALSE;
908     callback_output->Cancel = FALSE;
909     return TRUE;
910   }
911   // Ignore other callback types.
912   return FALSE;
913 }
914 
WriteMinidumpWithExceptionForProcess(DWORD requesting_thread_id,EXCEPTION_POINTERS * exinfo,MDRawAssertionInfo * assertion,HANDLE process,bool write_requester_stream)915 bool ExceptionHandler::WriteMinidumpWithExceptionForProcess(
916     DWORD requesting_thread_id,
917     EXCEPTION_POINTERS* exinfo,
918     MDRawAssertionInfo* assertion,
919     HANDLE process,
920     bool write_requester_stream) {
921   bool success = false;
922   if (minidump_write_dump_) {
923     HANDLE dump_file = CreateFile(next_minidump_path_c_,
924                                   GENERIC_WRITE,
925                                   0,  // no sharing
926                                   NULL,
927                                   CREATE_NEW,  // fail if exists
928                                   FILE_ATTRIBUTE_NORMAL,
929                                   NULL);
930     if (dump_file != INVALID_HANDLE_VALUE) {
931       MINIDUMP_EXCEPTION_INFORMATION except_info;
932       except_info.ThreadId = requesting_thread_id;
933       except_info.ExceptionPointers = exinfo;
934       except_info.ClientPointers = FALSE;
935 
936       // Leave room in user_stream_array for possible breakpad and
937       // assertion info streams.
938       MINIDUMP_USER_STREAM user_stream_array[2];
939       MINIDUMP_USER_STREAM_INFORMATION user_streams;
940       user_streams.UserStreamCount = 0;
941       user_streams.UserStreamArray = user_stream_array;
942 
943       if (write_requester_stream) {
944         // Add an MDRawBreakpadInfo stream to the minidump, to provide
945         // additional information about the exception handler to the Breakpad
946         // processor. The information will help the processor determine which
947         // threads are relevant.  The Breakpad processor does not require this
948         // information but can function better with Breakpad-generated dumps
949         // when it is present. The native debugger is not harmed by the
950         // presence of this information.
951         MDRawBreakpadInfo breakpad_info;
952         breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
953                                  MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
954         breakpad_info.dump_thread_id = GetCurrentThreadId();
955         breakpad_info.requesting_thread_id = requesting_thread_id;
956 
957         int index = user_streams.UserStreamCount;
958         user_stream_array[index].Type = MD_BREAKPAD_INFO_STREAM;
959         user_stream_array[index].BufferSize = sizeof(breakpad_info);
960         user_stream_array[index].Buffer = &breakpad_info;
961         ++user_streams.UserStreamCount;
962       }
963 
964       if (assertion) {
965         int index = user_streams.UserStreamCount;
966         user_stream_array[index].Type = MD_ASSERTION_INFO_STREAM;
967         user_stream_array[index].BufferSize = sizeof(MDRawAssertionInfo);
968         user_stream_array[index].Buffer = assertion;
969         ++user_streams.UserStreamCount;
970       }
971 
972       // Older versions of DbgHelp.dll don't correctly put the memory around
973       // the faulting instruction pointer into the minidump. This
974       // callback will ensure that it gets included.
975       if (exinfo) {
976         // Find a memory region of 256 bytes centered on the
977         // faulting instruction pointer.
978         const ULONG64 instruction_pointer =
979 #if defined(_M_IX86)
980           exinfo->ContextRecord->Eip;
981 #elif defined(_M_AMD64)
982           exinfo->ContextRecord->Rip;
983 #elif defined(_M_ARM64)
984           exinfo->ContextRecord->Pc;
985 #else
986 #error Unsupported platform
987 #endif
988 
989         MEMORY_BASIC_INFORMATION info;
990         if (VirtualQueryEx(process,
991                            reinterpret_cast<LPCVOID>(instruction_pointer),
992                            &info,
993                            sizeof(MEMORY_BASIC_INFORMATION)) != 0 &&
994             info.State == MEM_COMMIT) {
995           // Attempt to get 128 bytes before and after the instruction
996           // pointer, but settle for whatever's available up to the
997           // boundaries of the memory region.
998           const ULONG64 kIPMemorySize = 256;
999           ULONG64 base =
1000             (std::max)(reinterpret_cast<ULONG64>(info.BaseAddress),
1001                        instruction_pointer - (kIPMemorySize / 2));
1002           ULONG64 end_of_range =
1003             (std::min)(instruction_pointer + (kIPMemorySize / 2),
1004                        reinterpret_cast<ULONG64>(info.BaseAddress)
1005                        + info.RegionSize);
1006           ULONG size = static_cast<ULONG>(end_of_range - base);
1007 
1008           AppMemory& elt = app_memory_info_.front();
1009           elt.ptr = base;
1010           elt.length = size;
1011         }
1012       }
1013 
1014       MinidumpCallbackContext context;
1015       context.iter = app_memory_info_.begin();
1016       context.end = app_memory_info_.end();
1017 
1018       // Skip the reserved element if there was no instruction memory
1019       if (context.iter->ptr == 0) {
1020         context.iter++;
1021       }
1022 
1023       MINIDUMP_CALLBACK_INFORMATION callback;
1024       callback.CallbackRoutine = MinidumpWriteDumpCallback;
1025       callback.CallbackParam = reinterpret_cast<void*>(&context);
1026 
1027       // The explicit comparison to TRUE avoids a warning (C4800).
1028       success = (minidump_write_dump_(process,
1029                                       GetProcessId(process),
1030                                       dump_file,
1031                                       dump_type_,
1032                                       exinfo ? &except_info : NULL,
1033                                       &user_streams,
1034                                       &callback) == TRUE);
1035 
1036       CloseHandle(dump_file);
1037     }
1038   }
1039 
1040   return success;
1041 }
1042 
UpdateNextID()1043 void ExceptionHandler::UpdateNextID() {
1044   assert(uuid_create_);
1045   UUID id = {0};
1046   if (uuid_create_) {
1047     uuid_create_(&id);
1048   }
1049   next_minidump_id_ = GUIDString::GUIDToWString(&id);
1050   next_minidump_id_c_ = next_minidump_id_.c_str();
1051 
1052   wchar_t minidump_path[MAX_PATH];
1053   swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp",
1054            dump_path_c_, next_minidump_id_c_);
1055 
1056   // remove when VC++7.1 is no longer supported
1057   minidump_path[MAX_PATH - 1] = L'\0';
1058 
1059   next_minidump_path_ = minidump_path;
1060   next_minidump_path_c_ = next_minidump_path_.c_str();
1061 }
1062 
RegisterAppMemory(void * ptr,size_t length)1063 void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) {
1064   AppMemoryList::iterator iter =
1065     std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr);
1066   if (iter != app_memory_info_.end()) {
1067     // Don't allow registering the same pointer twice.
1068     return;
1069   }
1070 
1071   AppMemory app_memory;
1072   app_memory.ptr = reinterpret_cast<ULONG64>(ptr);
1073   app_memory.length = static_cast<ULONG>(length);
1074   app_memory_info_.push_back(app_memory);
1075 }
1076 
UnregisterAppMemory(void * ptr)1077 void ExceptionHandler::UnregisterAppMemory(void* ptr) {
1078   AppMemoryList::iterator iter =
1079     std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr);
1080   if (iter != app_memory_info_.end()) {
1081     app_memory_info_.erase(iter);
1082   }
1083 }
1084 
1085 }  // namespace google_breakpad
1086