• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
UnregisterException(EXCEPTION_REGISTRATION * registration)108   static void UnregisterException(EXCEPTION_REGISTRATION* registration) {
109     UnregisterExceptionRecord(registration);
110   }
111 };
112 
113 class EBReportAllTraits : public EBTraitsBase {
114  public:
RegisterException(EXCEPTION_REGISTRATION * registration)115   static void RegisterException(EXCEPTION_REGISTRATION* registration) {
116     RegisterExceptionRecord(registration, ExceptionBarrierHandler);
117   }
118 };
119 
120 class EBReportOnlyThisModuleTraits : public EBTraitsBase {
121  public:
RegisterException(EXCEPTION_REGISTRATION * registration)122   static void RegisterException(EXCEPTION_REGISTRATION* registration) {
123     RegisterExceptionRecord(registration,
124                             ExceptionBarrierReportOnlyModuleHandler);
125   }
126 };
127 
128 class EBCustomHandlerTraits : public EBTraitsBase {
129  public:
RegisterException(EXCEPTION_REGISTRATION * registration)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.
set_enabled(bool enabled)140   static void set_enabled(bool enabled) {
141     s_enabled_ = enabled;
142   }
enabled()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
ExceptionBarrierT()153   ExceptionBarrierT() {
154     RegistrarTraits::RegisterException(&registration_);
155   }
156 
157   // Unregister on destruction
~ExceptionBarrierT()158   virtual ~ExceptionBarrierT() {
159     RegistrarTraits::UnregisterException(&registration_);
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.
set_custom_handler(CustomExceptionHandler handler)180   static void set_custom_handler(CustomExceptionHandler handler) {
181     s_custom_handler_ = handler;
182   }
custom_handler()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