1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 // 5 // A class to make it easy to tag exception propagation boundaries and 6 // get crash reports of exceptions that pass over same. 7 // 8 // An exception barrier is used to report exceptions that pass through 9 // a boundary where exceptions shouldn't pass, such as e.g. COM interface 10 // boundaries. 11 // This is handy for any kind of plugin code, where if the exception passes 12 // through unhindered, it'll either be swallowed by an SEH exception handler 13 // above us on the stack, or be reported as an unhandled exception for 14 // the application hosting the plugin code. 15 // 16 // IMPORTANT NOTE: This class has crash_reporting disabled by default. To 17 // enable crash reporting call: 18 // 19 // @code 20 // ExceptionBarrierBase::set_crash_handling(true) 21 // @endcode 22 // 23 // somewhere in your initialization code. 24 // 25 // Then, to use this class, simply instantiate an ExceptionBarrier just inside 26 // the code boundary, like this: 27 // @code 28 // HRESULT SomeObject::SomeCOMMethod(...) { 29 // ExceptionBarrier report_crashes; 30 // 31 // ... other code here ... 32 // } 33 // @endcode 34 // 35 // There are three ExceptionBarrier types defined here: 36 // 1) ExceptionBarrier which reports all crashes it sees. 37 // 2) ExceptionBarrierReportOnlyModule which reports only crashes occurring 38 // in this module. 39 // 3) ExceptionBarrierCustomHandler which calls the handler set by a call 40 // to ExceptionBarrierCallCustomHandler::set_custom_handler(). Note that 41 // there is one custom handler for all ExceptionBarrierCallCustomHandler 42 // instances. If set_custom_handler() is never called, this places an 43 // SEH in the chain that just returns ExceptionContinueSearch. 44 45 #ifndef CHROME_FRAME_EXCEPTION_BARRIER_H_ 46 #define CHROME_FRAME_EXCEPTION_BARRIER_H_ 47 48 #include <windows.h> 49 50 extern "C" IMAGE_DOS_HEADER __ImageBase; 51 52 // This is the type dictated for an exception handler by the platform ABI 53 // @see _except_handler in excpt.h 54 typedef EXCEPTION_DISPOSITION (__cdecl* ExceptionHandlerFunc)( 55 struct _EXCEPTION_RECORD* exception_record, 56 void* establisher_frame, 57 struct _CONTEXT* context, 58 void* reserved); 59 60 // The type of an exception record in the exception handler chain 61 struct EXCEPTION_REGISTRATION { 62 EXCEPTION_REGISTRATION* prev; 63 ExceptionHandlerFunc handler; 64 }; 65 66 // This is our raw exception handler, it must be declared extern "C" to 67 // match up with the SAFESEH declaration in our corresponding ASM file. 68 extern "C" EXCEPTION_DISPOSITION __cdecl 69 ExceptionBarrierHandler(struct _EXCEPTION_RECORD* exception_record, 70 void* establisher_frame, 71 struct _CONTEXT* context, 72 void* reserved); 73 74 // An alternate raw exception handler that reports crashes only for the current 75 // module. It must be declared extern "C" to match up with the SAFESEH 76 // declaration in our corresponding ASM file. 77 extern "C" EXCEPTION_DISPOSITION __cdecl 78 ExceptionBarrierReportOnlyModuleHandler( 79 struct _EXCEPTION_RECORD* exception_record, 80 void* establisher_frame, 81 struct _CONTEXT* context, 82 void* reserved); 83 84 // An alternate raw exception handler that calls out to a custom handler. 85 // It must be declared extern "C" to match up with the SAFESEH declaration in 86 // our corresponding ASM file. 87 extern "C" EXCEPTION_DISPOSITION __cdecl 88 ExceptionBarrierCallCustomHandler( 89 struct _EXCEPTION_RECORD* exception_record, 90 void* establisher_frame, 91 struct _CONTEXT* context, 92 void* reserved); 93 94 95 // @name These are implemented in the associated .asm file 96 // @{ 97 extern "C" void WINAPI RegisterExceptionRecord( 98 EXCEPTION_REGISTRATION* registration, 99 ExceptionHandlerFunc func); 100 extern "C" void WINAPI UnregisterExceptionRecord( 101 EXCEPTION_REGISTRATION* registration); 102 // @} 103 104 105 // Traits classes for ExceptionBarrierT. 106 class EBTraitsBase { 107 public: 108 static void UnregisterException(EXCEPTION_REGISTRATION* registration) { 109 UnregisterExceptionRecord(registration); 110 } 111 }; 112 113 class EBReportAllTraits : public EBTraitsBase { 114 public: 115 static void RegisterException(EXCEPTION_REGISTRATION* registration) { 116 RegisterExceptionRecord(registration, ExceptionBarrierHandler); 117 } 118 }; 119 120 class EBReportOnlyThisModuleTraits : public EBTraitsBase { 121 public: 122 static void RegisterException(EXCEPTION_REGISTRATION* registration) { 123 RegisterExceptionRecord(registration, 124 ExceptionBarrierReportOnlyModuleHandler); 125 } 126 }; 127 128 class EBCustomHandlerTraits : public EBTraitsBase { 129 public: 130 static void RegisterException(EXCEPTION_REGISTRATION* registration) { 131 RegisterExceptionRecord(registration, 132 ExceptionBarrierCallCustomHandler); 133 } 134 }; 135 136 class ExceptionBarrierConfig { 137 public: 138 // Used to globally enable or disable crash handling by ExceptionBarrierBase 139 // instances. 140 static void set_enabled(bool enabled) { 141 s_enabled_ = enabled; 142 } 143 static bool enabled() { return s_enabled_; } 144 145 // Whether crash reports are enabled. 146 static bool s_enabled_; 147 }; 148 149 template <typename RegistrarTraits> 150 class ExceptionBarrierT { 151 public: 152 // Register the barrier in the SEH chain 153 ExceptionBarrierT() { 154 RegistrarTraits::RegisterException(®istration_); 155 } 156 157 // Unregister on destruction 158 virtual ~ExceptionBarrierT() { 159 RegistrarTraits::UnregisterException(®istration_); 160 } 161 162 protected: 163 // Our SEH frame 164 EXCEPTION_REGISTRATION registration_; 165 }; 166 167 // This class allows for setting a custom exception handler function. The 168 // handler is shared among all instances. This class is intended to enable 169 // testing of the SEH registration. 170 template <typename RegistrarTraits> 171 class ExceptionBarrierCustomHandlerT : 172 public ExceptionBarrierT<typename RegistrarTraits> { 173 public: 174 // Signature of the handler function which gets notified when 175 // an exception propagates through a barrier. 176 typedef void (CALLBACK* CustomExceptionHandler)(EXCEPTION_POINTERS* ptrs); 177 178 // Used to set a global custom handler used by all 179 // ExceptionBarrierCustomHandler instances. 180 static void set_custom_handler(CustomExceptionHandler handler) { 181 s_custom_handler_ = handler; 182 } 183 static CustomExceptionHandler custom_handler() { return s_custom_handler_; } 184 185 private: 186 static CustomExceptionHandler s_custom_handler_; 187 }; 188 189 // Convenience typedefs for the ExceptionBarrierT specializations. 190 typedef ExceptionBarrierT<EBReportAllTraits> ExceptionBarrier; 191 typedef ExceptionBarrierT<EBReportOnlyThisModuleTraits> 192 ExceptionBarrierReportOnlyModule; 193 typedef ExceptionBarrierCustomHandlerT<EBCustomHandlerTraits> 194 ExceptionBarrierCustomHandler; 195 196 #endif // CHROME_FRAME_EXCEPTION_BARRIER_H_ 197