1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,489 @@ 1.4 +// Copyright (c) 2006, Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// ExceptionHandler can write a minidump file when an exception occurs, 1.34 +// or when WriteMinidump() is called explicitly by your program. 1.35 +// 1.36 +// To have the exception handler write minidumps when an uncaught exception 1.37 +// (crash) occurs, you should create an instance early in the execution 1.38 +// of your program, and keep it around for the entire time you want to 1.39 +// have crash handling active (typically, until shutdown). 1.40 +// 1.41 +// If you want to write minidumps without installing the exception handler, 1.42 +// you can create an ExceptionHandler with install_handler set to false, 1.43 +// then call WriteMinidump. You can also use this technique if you want to 1.44 +// use different minidump callbacks for different call sites. 1.45 +// 1.46 +// In either case, a callback function is called when a minidump is written, 1.47 +// which receives the unqiue id of the minidump. The caller can use this 1.48 +// id to collect and write additional application state, and to launch an 1.49 +// external crash-reporting application. 1.50 +// 1.51 +// It is important that creation and destruction of ExceptionHandler objects 1.52 +// be nested cleanly, when using install_handler = true. 1.53 +// Avoid the following pattern: 1.54 +// ExceptionHandler *e = new ExceptionHandler(...); 1.55 +// ExceptionHandler *f = new ExceptionHandler(...); 1.56 +// delete e; 1.57 +// This will put the exception filter stack into an inconsistent state. 1.58 + 1.59 +#ifndef CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ 1.60 +#define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ 1.61 + 1.62 +#include <stdlib.h> 1.63 +#include <Windows.h> 1.64 +#include <DbgHelp.h> 1.65 +#include <rpc.h> 1.66 + 1.67 +#pragma warning( push ) 1.68 +// Disable exception handler warnings. 1.69 +#pragma warning( disable : 4530 ) 1.70 + 1.71 +#include <list> 1.72 +#include <string> 1.73 +#include <vector> 1.74 + 1.75 +#include "client/windows/common/ipc_protocol.h" 1.76 +#include "client/windows/crash_generation/crash_generation_client.h" 1.77 +#include "common/scoped_ptr.h" 1.78 +#include "google_breakpad/common/minidump_format.h" 1.79 + 1.80 +namespace google_breakpad { 1.81 + 1.82 +using std::vector; 1.83 +using std::wstring; 1.84 + 1.85 +// These entries store a list of memory regions that the client wants included 1.86 +// in the minidump. 1.87 +struct AppMemory { 1.88 + ULONG64 ptr; 1.89 + ULONG length; 1.90 + 1.91 + bool operator==(const struct AppMemory& other) const { 1.92 + return ptr == other.ptr; 1.93 + } 1.94 + 1.95 + bool operator==(const void* other) const { 1.96 + return ptr == reinterpret_cast<ULONG64>(other); 1.97 + } 1.98 +}; 1.99 +typedef std::list<AppMemory> AppMemoryList; 1.100 + 1.101 +class ExceptionHandler { 1.102 + public: 1.103 + // A callback function to run before Breakpad performs any substantial 1.104 + // processing of an exception. A FilterCallback is called before writing 1.105 + // a minidump. context is the parameter supplied by the user as 1.106 + // callback_context when the handler was created. exinfo points to the 1.107 + // exception record, if any; assertion points to assertion information, 1.108 + // if any. 1.109 + // 1.110 + // If a FilterCallback returns true, Breakpad will continue processing, 1.111 + // attempting to write a minidump. If a FilterCallback returns false, 1.112 + // Breakpad will immediately report the exception as unhandled without 1.113 + // writing a minidump, allowing another handler the opportunity to handle it. 1.114 + typedef bool (*FilterCallback)(void* context, EXCEPTION_POINTERS* exinfo, 1.115 + MDRawAssertionInfo* assertion); 1.116 + 1.117 + // A callback function to run after the minidump has been written. 1.118 + // minidump_id is a unique id for the dump, so the minidump 1.119 + // file is <dump_path>\<minidump_id>.dmp. context is the parameter supplied 1.120 + // by the user as callback_context when the handler was created. exinfo 1.121 + // points to the exception record, or NULL if no exception occurred. 1.122 + // succeeded indicates whether a minidump file was successfully written. 1.123 + // assertion points to information about an assertion if the handler was 1.124 + // invoked by an assertion. 1.125 + // 1.126 + // If an exception occurred and the callback returns true, Breakpad will treat 1.127 + // the exception as fully-handled, suppressing any other handlers from being 1.128 + // notified of the exception. If the callback returns false, Breakpad will 1.129 + // treat the exception as unhandled, and allow another handler to handle it. 1.130 + // If there are no other handlers, Breakpad will report the exception to the 1.131 + // system as unhandled, allowing a debugger or native crash dialog the 1.132 + // opportunity to handle the exception. Most callback implementations 1.133 + // should normally return the value of |succeeded|, or when they wish to 1.134 + // not report an exception of handled, false. Callbacks will rarely want to 1.135 + // return true directly (unless |succeeded| is true). 1.136 + // 1.137 + // For out-of-process dump generation, dump path and minidump ID will always 1.138 + // be NULL. In case of out-of-process dump generation, the dump path and 1.139 + // minidump id are controlled by the server process and are not communicated 1.140 + // back to the crashing process. 1.141 + typedef bool (*MinidumpCallback)(const wchar_t* dump_path, 1.142 + const wchar_t* minidump_id, 1.143 + void* context, 1.144 + EXCEPTION_POINTERS* exinfo, 1.145 + MDRawAssertionInfo* assertion, 1.146 + bool succeeded); 1.147 + 1.148 + // HandlerType specifies which types of handlers should be installed, if 1.149 + // any. Use HANDLER_NONE for an ExceptionHandler that remains idle, 1.150 + // without catching any failures on its own. This type of handler may 1.151 + // still be triggered by calling WriteMinidump. Otherwise, use a 1.152 + // combination of the other HANDLER_ values, or HANDLER_ALL to install 1.153 + // all handlers. 1.154 + enum HandlerType { 1.155 + HANDLER_NONE = 0, 1.156 + HANDLER_EXCEPTION = 1 << 0, // SetUnhandledExceptionFilter 1.157 + HANDLER_INVALID_PARAMETER = 1 << 1, // _set_invalid_parameter_handler 1.158 + HANDLER_PURECALL = 1 << 2, // _set_purecall_handler 1.159 + HANDLER_ALL = HANDLER_EXCEPTION | 1.160 + HANDLER_INVALID_PARAMETER | 1.161 + HANDLER_PURECALL 1.162 + }; 1.163 + 1.164 + // Creates a new ExceptionHandler instance to handle writing minidumps. 1.165 + // Before writing a minidump, the optional filter callback will be called. 1.166 + // Its return value determines whether or not Breakpad should write a 1.167 + // minidump. Minidump files will be written to dump_path, and the optional 1.168 + // callback is called after writing the dump file, as described above. 1.169 + // handler_types specifies the types of handlers that should be installed. 1.170 + ExceptionHandler(const wstring& dump_path, 1.171 + FilterCallback filter, 1.172 + MinidumpCallback callback, 1.173 + void* callback_context, 1.174 + int handler_types); 1.175 + 1.176 + // Creates a new ExceptionHandler instance that can attempt to perform 1.177 + // out-of-process dump generation if pipe_name is not NULL. If pipe_name is 1.178 + // NULL, or if out-of-process dump generation registration step fails, 1.179 + // in-process dump generation will be used. This also allows specifying 1.180 + // the dump type to generate. 1.181 + ExceptionHandler(const wstring& dump_path, 1.182 + FilterCallback filter, 1.183 + MinidumpCallback callback, 1.184 + void* callback_context, 1.185 + int handler_types, 1.186 + MINIDUMP_TYPE dump_type, 1.187 + const wchar_t* pipe_name, 1.188 + const CustomClientInfo* custom_info); 1.189 + 1.190 + // As above, creates a new ExceptionHandler instance to perform 1.191 + // out-of-process dump generation if the given pipe_handle is not NULL. 1.192 + ExceptionHandler(const wstring& dump_path, 1.193 + FilterCallback filter, 1.194 + MinidumpCallback callback, 1.195 + void* callback_context, 1.196 + int handler_types, 1.197 + MINIDUMP_TYPE dump_type, 1.198 + HANDLE pipe_handle, 1.199 + const CustomClientInfo* custom_info); 1.200 + 1.201 + ~ExceptionHandler(); 1.202 + 1.203 + // Get and set the minidump path. 1.204 + wstring dump_path() const { return dump_path_; } 1.205 + void set_dump_path(const wstring &dump_path) { 1.206 + dump_path_ = dump_path; 1.207 + dump_path_c_ = dump_path_.c_str(); 1.208 + UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_. 1.209 + } 1.210 + 1.211 + // Requests that a previously reported crash be uploaded. 1.212 + bool RequestUpload(DWORD crash_id); 1.213 + 1.214 + // Writes a minidump immediately. This can be used to capture the 1.215 + // execution state independently of a crash. Returns true on success. 1.216 + bool WriteMinidump(); 1.217 + 1.218 + // Writes a minidump immediately, with the user-supplied exception 1.219 + // information. 1.220 + bool WriteMinidumpForException(EXCEPTION_POINTERS* exinfo); 1.221 + 1.222 + // Convenience form of WriteMinidump which does not require an 1.223 + // ExceptionHandler instance. 1.224 + static bool WriteMinidump(const wstring &dump_path, 1.225 + MinidumpCallback callback, void* callback_context); 1.226 + 1.227 + // Write a minidump of |child| immediately. This can be used to 1.228 + // capture the execution state of |child| independently of a crash. 1.229 + // Pass a meaningful |child_blamed_thread| to make that thread in 1.230 + // the child process the one from which a crash signature is 1.231 + // extracted. 1.232 + static bool WriteMinidumpForChild(HANDLE child, 1.233 + DWORD child_blamed_thread, 1.234 + const wstring& dump_path, 1.235 + MinidumpCallback callback, 1.236 + void* callback_context); 1.237 + 1.238 + // Get the thread ID of the thread requesting the dump (either the exception 1.239 + // thread or any other thread that called WriteMinidump directly). This 1.240 + // may be useful if you want to include additional thread state in your 1.241 + // dumps. 1.242 + DWORD get_requesting_thread_id() const { return requesting_thread_id_; } 1.243 + 1.244 + // Controls behavior of EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP. 1.245 + bool get_handle_debug_exceptions() const { return handle_debug_exceptions_; } 1.246 + void set_handle_debug_exceptions(bool handle_debug_exceptions) { 1.247 + handle_debug_exceptions_ = handle_debug_exceptions; 1.248 + } 1.249 + 1.250 + // Returns whether out-of-process dump generation is used or not. 1.251 + bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; } 1.252 + 1.253 + // Calling RegisterAppMemory(p, len) causes len bytes starting 1.254 + // at address p to be copied to the minidump when a crash happens. 1.255 + void RegisterAppMemory(void* ptr, size_t length); 1.256 + void UnregisterAppMemory(void* ptr); 1.257 + 1.258 + private: 1.259 + friend class AutoExceptionHandler; 1.260 + 1.261 + // Initializes the instance with given values. 1.262 + void Initialize(const wstring& dump_path, 1.263 + FilterCallback filter, 1.264 + MinidumpCallback callback, 1.265 + void* callback_context, 1.266 + int handler_types, 1.267 + MINIDUMP_TYPE dump_type, 1.268 + const wchar_t* pipe_name, 1.269 + HANDLE pipe_handle, 1.270 + const CustomClientInfo* custom_info); 1.271 + 1.272 + // Function pointer type for MiniDumpWriteDump, which is looked up 1.273 + // dynamically. 1.274 + typedef BOOL (WINAPI *MiniDumpWriteDump_type)( 1.275 + HANDLE hProcess, 1.276 + DWORD dwPid, 1.277 + HANDLE hFile, 1.278 + MINIDUMP_TYPE DumpType, 1.279 + CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, 1.280 + CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, 1.281 + CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); 1.282 + 1.283 + // Function pointer type for UuidCreate, which is looked up dynamically. 1.284 + typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID* Uuid); 1.285 + 1.286 + // Runs the main loop for the exception handler thread. 1.287 + static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter); 1.288 + 1.289 + // Called on the exception thread when an unhandled exception occurs. 1.290 + // Signals the exception handler thread to handle the exception. 1.291 + static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo); 1.292 + 1.293 +#if _MSC_VER >= 1400 // MSVC 2005/8 1.294 + // This function will be called by some CRT functions when they detect 1.295 + // that they were passed an invalid parameter. Note that in _DEBUG builds, 1.296 + // the CRT may display an assertion dialog before calling this function, 1.297 + // and the function will not be called unless the assertion dialog is 1.298 + // dismissed by clicking "Ignore." 1.299 + static void HandleInvalidParameter(const wchar_t* expression, 1.300 + const wchar_t* function, 1.301 + const wchar_t* file, 1.302 + unsigned int line, 1.303 + uintptr_t reserved); 1.304 +#endif // _MSC_VER >= 1400 1.305 + 1.306 + // This function will be called by the CRT when a pure virtual 1.307 + // function is called. 1.308 + static void HandlePureVirtualCall(); 1.309 + 1.310 + // This is called on the exception thread or on another thread that 1.311 + // the user wishes to produce a dump from. It calls 1.312 + // WriteMinidumpWithException on the handler thread, avoiding stack 1.313 + // overflows and inconsistent dumps due to writing the dump from 1.314 + // the exception thread. If the dump is requested as a result of an 1.315 + // exception, exinfo contains exception information, otherwise, it 1.316 + // is NULL. If the dump is requested as a result of an assertion 1.317 + // (such as an invalid parameter being passed to a CRT function), 1.318 + // assertion contains data about the assertion, otherwise, it is NULL. 1.319 + bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS* exinfo, 1.320 + MDRawAssertionInfo* assertion); 1.321 + 1.322 + // This function is called on the handler thread. It calls into 1.323 + // WriteMinidumpWithExceptionForProcess() with a handle to the 1.324 + // current process. requesting_thread_id is the ID of the thread 1.325 + // that requested the dump. If the dump is requested as a result of 1.326 + // an exception, exinfo contains exception information, otherwise, 1.327 + // it is NULL. 1.328 + bool WriteMinidumpWithException(DWORD requesting_thread_id, 1.329 + EXCEPTION_POINTERS* exinfo, 1.330 + MDRawAssertionInfo* assertion); 1.331 + 1.332 + // This function is used as a callback when calling MinidumpWriteDump, 1.333 + // in order to add additional memory regions to the dump. 1.334 + static BOOL CALLBACK MinidumpWriteDumpCallback( 1.335 + PVOID context, 1.336 + const PMINIDUMP_CALLBACK_INPUT callback_input, 1.337 + PMINIDUMP_CALLBACK_OUTPUT callback_output); 1.338 + 1.339 + // This function does the actual writing of a minidump. It is 1.340 + // called on the handler thread. requesting_thread_id is the ID of 1.341 + // the thread that requested the dump, if that information is 1.342 + // meaningful. If the dump is requested as a result of an 1.343 + // exception, exinfo contains exception information, otherwise, it 1.344 + // is NULL. process is the one that will be dumped. If 1.345 + // requesting_thread_id is meaningful and should be added to the 1.346 + // minidump, write_requester_stream is |true|. 1.347 + bool WriteMinidumpWithExceptionForProcess(DWORD requesting_thread_id, 1.348 + EXCEPTION_POINTERS* exinfo, 1.349 + MDRawAssertionInfo* assertion, 1.350 + HANDLE process, 1.351 + bool write_requester_stream); 1.352 + 1.353 + // Generates a new ID and stores it in next_minidump_id_, and stores the 1.354 + // path of the next minidump to be written in next_minidump_path_. 1.355 + void UpdateNextID(); 1.356 + 1.357 + FilterCallback filter_; 1.358 + MinidumpCallback callback_; 1.359 + void* callback_context_; 1.360 + 1.361 + scoped_ptr<CrashGenerationClient> crash_generation_client_; 1.362 + 1.363 + // The directory in which a minidump will be written, set by the dump_path 1.364 + // argument to the constructor, or set_dump_path. 1.365 + wstring dump_path_; 1.366 + 1.367 + // The basename of the next minidump to be written, without the extension. 1.368 + wstring next_minidump_id_; 1.369 + 1.370 + // The full pathname of the next minidump to be written, including the file 1.371 + // extension. 1.372 + wstring next_minidump_path_; 1.373 + 1.374 + // Pointers to C-string representations of the above. These are set when 1.375 + // the above wstring versions are set in order to avoid calling c_str during 1.376 + // an exception, as c_str may attempt to allocate heap memory. These 1.377 + // pointers are not owned by the ExceptionHandler object, but their lifetimes 1.378 + // should be equivalent to the lifetimes of the associated wstring, provided 1.379 + // that the wstrings are not altered. 1.380 + const wchar_t* dump_path_c_; 1.381 + const wchar_t* next_minidump_id_c_; 1.382 + const wchar_t* next_minidump_path_c_; 1.383 + 1.384 + HMODULE dbghelp_module_; 1.385 + MiniDumpWriteDump_type minidump_write_dump_; 1.386 + MINIDUMP_TYPE dump_type_; 1.387 + 1.388 + HMODULE rpcrt4_module_; 1.389 + UuidCreate_type uuid_create_; 1.390 + 1.391 + // Tracks the handler types that were installed according to the 1.392 + // handler_types constructor argument. 1.393 + int handler_types_; 1.394 + 1.395 + // When installed_handler_ is true, previous_filter_ is the unhandled 1.396 + // exception filter that was set prior to installing ExceptionHandler as 1.397 + // the unhandled exception filter and pointing it to |this|. NULL indicates 1.398 + // that there is no previous unhandled exception filter. 1.399 + LPTOP_LEVEL_EXCEPTION_FILTER previous_filter_; 1.400 + 1.401 +#if _MSC_VER >= 1400 // MSVC 2005/8 1.402 + // Beginning in VC 8, the CRT provides an invalid parameter handler that will 1.403 + // be called when some CRT functions are passed invalid parameters. In 1.404 + // earlier CRTs, the same conditions would cause unexpected behavior or 1.405 + // crashes. 1.406 + _invalid_parameter_handler previous_iph_; 1.407 +#endif // _MSC_VER >= 1400 1.408 + 1.409 + // The CRT allows you to override the default handler for pure 1.410 + // virtual function calls. 1.411 + _purecall_handler previous_pch_; 1.412 + 1.413 + // The exception handler thread. 1.414 + HANDLE handler_thread_; 1.415 + 1.416 + // True if the exception handler is being destroyed. 1.417 + // Starting with MSVC 2005, Visual C has stronger guarantees on volatile vars. 1.418 + // It has release semantics on write and acquire semantics on reads. 1.419 + // See the msdn documentation. 1.420 + volatile bool is_shutdown_; 1.421 + 1.422 + // The critical section enforcing the requirement that only one exception be 1.423 + // handled by a handler at a time. 1.424 + CRITICAL_SECTION handler_critical_section_; 1.425 + 1.426 + // Semaphores used to move exception handling between the exception thread 1.427 + // and the handler thread. handler_start_semaphore_ is signalled by the 1.428 + // exception thread to wake up the handler thread when an exception occurs. 1.429 + // handler_finish_semaphore_ is signalled by the handler thread to wake up 1.430 + // the exception thread when handling is complete. 1.431 + HANDLE handler_start_semaphore_; 1.432 + HANDLE handler_finish_semaphore_; 1.433 + 1.434 + // The next 2 fields contain data passed from the requesting thread to 1.435 + // the handler thread. 1.436 + 1.437 + // The thread ID of the thread requesting the dump (either the exception 1.438 + // thread or any other thread that called WriteMinidump directly). 1.439 + DWORD requesting_thread_id_; 1.440 + 1.441 + // The exception info passed to the exception handler on the exception 1.442 + // thread, if an exception occurred. NULL for user-requested dumps. 1.443 + EXCEPTION_POINTERS* exception_info_; 1.444 + 1.445 + // If the handler is invoked due to an assertion, this will contain a 1.446 + // pointer to the assertion information. It is NULL at other times. 1.447 + MDRawAssertionInfo* assertion_; 1.448 + 1.449 + // The return value of the handler, passed from the handler thread back to 1.450 + // the requesting thread. 1.451 + bool handler_return_value_; 1.452 + 1.453 + // If true, the handler will intercept EXCEPTION_BREAKPOINT and 1.454 + // EXCEPTION_SINGLE_STEP exceptions. Leave this false (the default) 1.455 + // to not interfere with debuggers. 1.456 + bool handle_debug_exceptions_; 1.457 + 1.458 + // Callers can request additional memory regions to be included in 1.459 + // the dump. 1.460 + AppMemoryList app_memory_info_; 1.461 + 1.462 + // A stack of ExceptionHandler objects that have installed unhandled 1.463 + // exception filters. This vector is used by HandleException to determine 1.464 + // which ExceptionHandler object to route an exception to. When an 1.465 + // ExceptionHandler is created with install_handler true, it will append 1.466 + // itself to this list. 1.467 + static vector<ExceptionHandler*>* handler_stack_; 1.468 + 1.469 + // The index of the ExceptionHandler in handler_stack_ that will handle the 1.470 + // next exception. Note that 0 means the last entry in handler_stack_, 1 1.471 + // means the next-to-last entry, and so on. This is used by HandleException 1.472 + // to support multiple stacked Breakpad handlers. 1.473 + static LONG handler_stack_index_; 1.474 + 1.475 + // handler_stack_critical_section_ guards operations on handler_stack_ and 1.476 + // handler_stack_index_. The critical section is initialized by the 1.477 + // first instance of the class and destroyed by the last instance of it. 1.478 + static CRITICAL_SECTION handler_stack_critical_section_; 1.479 + 1.480 + // The number of instances of this class. 1.481 + volatile static LONG instance_count_; 1.482 + 1.483 + // disallow copy ctor and operator= 1.484 + explicit ExceptionHandler(const ExceptionHandler &); 1.485 + void operator=(const ExceptionHandler &); 1.486 +}; 1.487 + 1.488 +} // namespace google_breakpad 1.489 + 1.490 +#pragma warning( pop ) 1.491 + 1.492 +#endif // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__