// 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_