| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 // |
| 5 // A class to make it easy to tag exception propagation boundaries and | 5 // A class to make it easy to tag exception propagation boundaries and |
| 6 // get crash reports of exceptions that pass over same. | 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 |
| 7 #ifndef CHROME_FRAME_EXCEPTION_BARRIER_H_ | 45 #ifndef CHROME_FRAME_EXCEPTION_BARRIER_H_ |
| 8 #define CHROME_FRAME_EXCEPTION_BARRIER_H_ | 46 #define CHROME_FRAME_EXCEPTION_BARRIER_H_ |
| 9 | 47 |
| 10 #include <windows.h> | 48 #include <windows.h> |
| 11 | 49 |
| 12 /// This is the type dictated for an exception handler by the platform ABI | 50 extern "C" IMAGE_DOS_HEADER __ImageBase; |
| 13 /// @see _except_handler in excpt.h | |
| 14 typedef EXCEPTION_DISPOSITION (__cdecl *ExceptionHandlerFunc)( | |
| 15 struct _EXCEPTION_RECORD *exception_record, | |
| 16 void * establisher_frame, | |
| 17 struct _CONTEXT *context, | |
| 18 void * reserved); | |
| 19 | 51 |
| 20 /// The type of an exception record in the exception handler chain | 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 |
| 21 struct EXCEPTION_REGISTRATION { | 61 struct EXCEPTION_REGISTRATION { |
| 22 EXCEPTION_REGISTRATION *prev; | 62 EXCEPTION_REGISTRATION* prev; |
| 23 ExceptionHandlerFunc handler; | 63 ExceptionHandlerFunc handler; |
| 24 }; | 64 }; |
| 25 | 65 |
| 26 /// This is our raw exception handler, it must be declared extern "C" to | 66 // This is our raw exception handler, it must be declared extern "C" to |
| 27 /// match up with the SAFESEH declaration in our corresponding ASM file | 67 // match up with the SAFESEH declaration in our corresponding ASM file. |
| 28 extern "C" EXCEPTION_DISPOSITION __cdecl | 68 extern "C" EXCEPTION_DISPOSITION __cdecl |
| 29 ExceptionBarrierHandler(struct _EXCEPTION_RECORD *exception_record, | 69 ExceptionBarrierHandler(struct _EXCEPTION_RECORD* exception_record, |
| 30 void * establisher_frame, | 70 void* establisher_frame, |
| 31 struct _CONTEXT *context, | 71 struct _CONTEXT* context, |
| 32 void * reserved); | 72 void* reserved); |
| 33 | 73 |
| 34 /// An exception barrier is used to report exceptions that pass through | 74 // An alternate raw exception handler that reports crashes only for the current |
| 35 /// a boundary where exceptions shouldn't pass, such as e.g. COM interface | 75 // module. It must be declared extern "C" to match up with the SAFESEH |
| 36 /// boundaries. | 76 // declaration in our corresponding ASM file. |
| 37 /// This is handy for any kind of plugin code, where if the exception passes | 77 extern "C" EXCEPTION_DISPOSITION __cdecl |
| 38 /// through unhindered, it'll either be swallowed by an SEH exception handler | 78 ExceptionBarrierReportOnlyModuleHandler( |
| 39 /// above us on the stack, or be reported as an unhandled exception for | 79 struct _EXCEPTION_RECORD* exception_record, |
| 40 /// the application hosting the plugin code. | 80 void* establisher_frame, |
| 41 /// | 81 struct _CONTEXT* context, |
| 42 /// To use this class, simply instantiate an ExceptionBarrier just inside | 82 void* reserved); |
| 43 /// the code boundary, like this: | 83 |
| 44 /// @code | 84 // An alternate raw exception handler that calls out to a custom handler. |
| 45 /// HRESULT SomeObject::SomeCOMMethod(...) { | 85 // It must be declared extern "C" to match up with the SAFESEH declaration in |
| 46 /// ExceptionBarrier report_crashes; | 86 // our corresponding ASM file. |
| 47 /// | 87 extern "C" EXCEPTION_DISPOSITION __cdecl |
| 48 /// ... other code here ... | 88 ExceptionBarrierCallCustomHandler( |
| 49 /// } | 89 struct _EXCEPTION_RECORD* exception_record, |
| 50 /// @endcode | 90 void* establisher_frame, |
| 51 class ExceptionBarrier { | 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 { |
| 52 public: | 107 public: |
| 53 /// Register the barrier in the SEH chain | 108 static void UnregisterException(EXCEPTION_REGISTRATION* registration) { |
| 54 ExceptionBarrier(); | 109 UnregisterExceptionRecord(registration); |
| 110 } |
| 111 }; |
| 55 | 112 |
| 56 /// And unregister on destruction | 113 class EBReportAllTraits : public EBTraitsBase { |
| 57 ~ExceptionBarrier(); | 114 public: |
| 115 static void RegisterException(EXCEPTION_REGISTRATION* registration) { |
| 116 RegisterExceptionRecord(registration, ExceptionBarrierHandler); |
| 117 } |
| 118 }; |
| 58 | 119 |
| 59 /// Signature of the handler function which gets notified when | 120 class EBReportOnlyThisModuleTraits : public EBTraitsBase { |
| 60 /// an exception propagates through a barrier. | 121 public: |
| 61 typedef void (CALLBACK *ExceptionHandler)(EXCEPTION_POINTERS *ptrs); | 122 static void RegisterException(EXCEPTION_REGISTRATION* registration) { |
| 123 RegisterExceptionRecord(registration, |
| 124 ExceptionBarrierReportOnlyModuleHandler); |
| 125 } |
| 126 }; |
| 62 | 127 |
| 63 /// @name Accessors | 128 class EBCustomHandlerTraits : public EBTraitsBase { |
| 64 /// @{ | 129 public: |
| 65 static void set_handler(ExceptionHandler handler) { s_handler_ = handler; } | 130 static void RegisterException(EXCEPTION_REGISTRATION* registration) { |
| 66 static ExceptionHandler handler() { return s_handler_; } | 131 RegisterExceptionRecord(registration, |
| 67 /// @} | 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_; } |
| 68 | 184 |
| 69 private: | 185 private: |
| 70 /// Our SEH frame | 186 static CustomExceptionHandler s_custom_handler_; |
| 71 EXCEPTION_REGISTRATION registration_; | |
| 72 | |
| 73 /// The function that gets invoked if an exception | |
| 74 /// propagates through a barrier | |
| 75 static ExceptionHandler s_handler_; | |
| 76 }; | 187 }; |
| 77 | 188 |
| 78 /// @name These are implemented in the associated .asm file | 189 // Convenience typedefs for the ExceptionBarrierT specializations. |
| 79 /// @{ | 190 typedef ExceptionBarrierT<EBReportAllTraits> ExceptionBarrier; |
| 80 extern "C" void WINAPI RegisterExceptionRecord( | 191 typedef ExceptionBarrierT<EBReportOnlyThisModuleTraits> |
| 81 EXCEPTION_REGISTRATION *registration, | 192 ExceptionBarrierReportOnlyModule; |
| 82 ExceptionHandlerFunc func); | 193 typedef ExceptionBarrierCustomHandlerT<EBCustomHandlerTraits> |
| 83 extern "C" void WINAPI UnregisterExceptionRecord( | 194 ExceptionBarrierCustomHandler; |
| 84 EXCEPTION_REGISTRATION *registration); | |
| 85 /// @} | |
| 86 | |
| 87 | |
| 88 inline ExceptionBarrier::ExceptionBarrier() { | |
| 89 RegisterExceptionRecord(®istration_, ExceptionBarrierHandler); | |
| 90 } | |
| 91 | |
| 92 inline ExceptionBarrier::~ExceptionBarrier() { | |
| 93 UnregisterExceptionRecord(®istration_); | |
| 94 } | |
| 95 | 195 |
| 96 #endif // CHROME_FRAME_EXCEPTION_BARRIER_H_ | 196 #endif // CHROME_FRAME_EXCEPTION_BARRIER_H_ |
| OLD | NEW |