// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // A class to make it easy to tag exception propagation boundaries and // get crash reports of exceptions that pass over same. // // An exception barrier is used to report exceptions that pass through // a boundary where exceptions shouldn't pass, such as e.g. COM interface // boundaries. // This is handy for any kind of plugin code, where if the exception passes // through unhindered, it'll either be swallowed by an SEH exception handler // above us on the stack, or be reported as an unhandled exception for // the application hosting the plugin code. // // IMPORTANT NOTE: This class has crash_reporting disabled by default. To // enable crash reporting call: // // @code // ExceptionBarrierBase::set_crash_handling(true) // @endcode // // somewhere in your initialization code. // // Then, to use this class, simply instantiate an ExceptionBarrier just inside // the code boundary, like this: // @code // HRESULT SomeObject::SomeCOMMethod(...) { // ExceptionBarrier report_crashes; // // ... other code here ... // } // @endcode // // There are three ExceptionBarrier types defined here: // 1) ExceptionBarrier which reports all crashes it sees. // 2) ExceptionBarrierReportOnlyModule which reports only crashes occurring // in this module. // 3) ExceptionBarrierCustomHandler which calls the handler set by a call // to ExceptionBarrierCallCustomHandler::set_custom_handler(). Note that // there is one custom handler for all ExceptionBarrierCallCustomHandler // instances. If set_custom_handler() is never called, this places an // SEH in the chain that just returns ExceptionContinueSearch. #ifndef CHROME_FRAME_EXCEPTION_BARRIER_H_ #define CHROME_FRAME_EXCEPTION_BARRIER_H_ #include <windows.h> extern "C" IMAGE_DOS_HEADER __ImageBase; // This is the type dictated for an exception handler by the platform ABI // @see _except_handler in excpt.h typedef EXCEPTION_DISPOSITION (__cdecl* ExceptionHandlerFunc)( struct _EXCEPTION_RECORD* exception_record, void* establisher_frame, struct _CONTEXT* context, void* reserved); // The type of an exception record in the exception handler chain struct EXCEPTION_REGISTRATION { EXCEPTION_REGISTRATION* prev; ExceptionHandlerFunc handler; }; // This is our raw exception handler, it must be declared extern "C" to // match up with the SAFESEH declaration in our corresponding ASM file. extern "C" EXCEPTION_DISPOSITION __cdecl ExceptionBarrierHandler(struct _EXCEPTION_RECORD* exception_record, void* establisher_frame, struct _CONTEXT* context, void* reserved); // An alternate raw exception handler that reports crashes only for the current // module. It must be declared extern "C" to match up with the SAFESEH // declaration in our corresponding ASM file. extern "C" EXCEPTION_DISPOSITION __cdecl ExceptionBarrierReportOnlyModuleHandler( struct _EXCEPTION_RECORD* exception_record, void* establisher_frame, struct _CONTEXT* context, void* reserved); // An alternate raw exception handler that calls out to a custom handler. // It must be declared extern "C" to match up with the SAFESEH declaration in // our corresponding ASM file. extern "C" EXCEPTION_DISPOSITION __cdecl ExceptionBarrierCallCustomHandler( struct _EXCEPTION_RECORD* exception_record, void* establisher_frame, struct _CONTEXT* context, void* reserved); // @name These are implemented in the associated .asm file // @{ extern "C" void WINAPI RegisterExceptionRecord( EXCEPTION_REGISTRATION* registration, ExceptionHandlerFunc func); extern "C" void WINAPI UnregisterExceptionRecord( EXCEPTION_REGISTRATION* registration); // @} // Traits classes for ExceptionBarrierT. class EBTraitsBase { public: static void UnregisterException(EXCEPTION_REGISTRATION* registration) { UnregisterExceptionRecord(registration); } }; class EBReportAllTraits : public EBTraitsBase { public: static void RegisterException(EXCEPTION_REGISTRATION* registration) { RegisterExceptionRecord(registration, ExceptionBarrierHandler); } }; class EBReportOnlyThisModuleTraits : public EBTraitsBase { public: static void RegisterException(EXCEPTION_REGISTRATION* registration) { RegisterExceptionRecord(registration, ExceptionBarrierReportOnlyModuleHandler); } }; class EBCustomHandlerTraits : public EBTraitsBase { public: static void RegisterException(EXCEPTION_REGISTRATION* registration) { RegisterExceptionRecord(registration, ExceptionBarrierCallCustomHandler); } }; class ExceptionBarrierConfig { public: // Used to globally enable or disable crash handling by ExceptionBarrierBase // instances. static void set_enabled(bool enabled) { s_enabled_ = enabled; } static bool enabled() { return s_enabled_; } // Whether crash reports are enabled. static bool s_enabled_; }; template <typename RegistrarTraits> class ExceptionBarrierT { public: // Register the barrier in the SEH chain ExceptionBarrierT() { RegistrarTraits::RegisterException(®istration_); } // Unregister on destruction virtual ~ExceptionBarrierT() { RegistrarTraits::UnregisterException(®istration_); } protected: // Our SEH frame EXCEPTION_REGISTRATION registration_; }; // This class allows for setting a custom exception handler function. The // handler is shared among all instances. This class is intended to enable // testing of the SEH registration. template <typename RegistrarTraits> class ExceptionBarrierCustomHandlerT : public ExceptionBarrierT<typename RegistrarTraits> { public: // Signature of the handler function which gets notified when // an exception propagates through a barrier. typedef void (CALLBACK* CustomExceptionHandler)(EXCEPTION_POINTERS* ptrs); // Used to set a global custom handler used by all // ExceptionBarrierCustomHandler instances. static void set_custom_handler(CustomExceptionHandler handler) { s_custom_handler_ = handler; } static CustomExceptionHandler custom_handler() { return s_custom_handler_; } private: static CustomExceptionHandler s_custom_handler_; }; // Convenience typedefs for the ExceptionBarrierT specializations. typedef ExceptionBarrierT<EBReportAllTraits> ExceptionBarrier; typedef ExceptionBarrierT<EBReportOnlyThisModuleTraits> ExceptionBarrierReportOnlyModule; typedef ExceptionBarrierCustomHandlerT<EBCustomHandlerTraits> ExceptionBarrierCustomHandler; #endif // CHROME_FRAME_EXCEPTION_BARRIER_H_