快速业务通道

C++编译器如何实现异常处理

作者 佚名技术 来源 程序设计 浏览 发布时间 2012-06-30
基类对象,并且发生异常时它们中的一部分已经构造完成的话,就必须调用这些对象的析构函数。和普通函数一样,编译器也给构造函数生成了相关的数据来帮助完成这个任务。

展开堆栈时,异常处理程序调用的是用户定义的析构函数,这一点你必须注意,因为它也有可能抛出异常!C++标准规定堆栈展开过程中,析构函数不能抛出异常,否则系统将调用std::terminate。

实现

本节我们讨论其他三个有待详细解释的问题:

a)如何安装异常处理程序

b)catch块重新抛出异常或抛出新异常时应该如何处理

c)如何对所有线程提供异常处理支持

随同本文,有一个演示项目,查看其中的readme.txt文件可以得到一些编译方面的帮助①。

第一项任务是安装异常处理程序,也就是把VC++的处理程序替换掉。从前面的讨论中,我们已经清楚地知道__CxxFrameHandler函数是VC++所有异常处理工作的入口。编译器为每个函数都生成一段代码,它们在发生异常时被调用,把相应的funcinfo结构的指针交给__CxxFrameHandler。

install_my_handler()函数会改写__CxxFrameHandler的入口处的代码,让程序跳转到my_exc_handler()函数。不过,__CxxFrameHandler位于只读的内存页,对它的任何写操作都会导致访问违例,所以必须首先用VirtualProtectEx把该内存页的保护方式改成可读写,等改写完毕后,再改回只读。写入的数据是一个jmp_instr结构。

//install_my_handler.cpp
#include <windows.h>
#include "install_my_handler.h"
//C++默认的异常处理程序
extern "C"
EXCEPTION_DISPOSITION __CxxFrameHandler(
  struct _EXCEPTION_RECORD* ExceptionRecord,
  void* EstablisherFrame,
  struct _CONTEXT* ContextRecord,
  void* DispatcherContext
  );
namespace
{
  char cpp_handler_instructions[5];
  bool saved_handler_instructions = false;
}
namespace my_handler
{
  //我的异常处理程序 EXCEPTION_DISPOSITION
  my_exc_handler(
    struct _EXCEPTION_RECORD *ExceptionRecord,
    void * EstablisherFrame,
    struct _CONTEXT *ContextRecord,
    void * DispatcherContext
  ) throw();
#pragma pack(push, 1)
  struct jmp_instr
  {
    unsigned char jmp;
    DWORD offset;
  };
#pragma pack(pop)
  bool WriteMemory(void* loc, void* buffer, int size)
  {
    HANDLE hProcess = GetCurrentProcess();
    //把包含内存范围[loc,loc+size]的页面的保护方式改成可读写
    DWORD old_protection;
    BOOL ret = VirtualProtectEx(hProcess, loc, size, PAGE_READWRITE, &old_protection);
    if(ret == FALSE)
      return false;
    ret = WriteProcessMemory(hProcess, loc, buffer, size, NULL);
    //恢复原来的保护方式
    DWORD o2;
    VirtualProtectEx(hProcess, loc, size, old_protection, &o2);
    return (ret == TRUE);
  }
  bool ReadMemory(void* loc, void* buffer, DWORD size)
  {
    HANDLE hProcess = GetCurrentProcess();
    DWORD bytes_read = 0;
    BOOL ret = ReadProcessMemory(hProcess, loc, buffer, size, &bytes_read);
    return (ret == TRUE && bytes_read == size);
  }
  bool install_my_handler()
  {
    void* my_hdlr = my_exc_handler; void* cpp_hdlr = __CxxFrameHandler;
    jmp_instr jmp_my_hdlr;
    jmp_my_hdlr.jmp = 0xE9;
    //从__CxxFrameHandler+5开始计算偏移,因为jmp指令长5字节
    jmp_my_hdlr.offset = reinterpret_ca

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号