VC++异常处理

Windows下的C++程序一般会有如下的异常:

o    操作系统产生的SHE

o    C运行库产生CRT错误

o    信号

每一种异常都需要安装exception handler函数来处理这些异常,以此来防止程序由于这些异常而crash,或者在程序因异常而退出时留下遗言,主要是打印出当时的栈信息,方便我们对其进行分析。

如果应用程序是多线程,那么情况变得复杂了。因为有的handler工作在整个进程,而有的工作只是工作在当前线程,此时需要为每一个线程安装handler。

而异常产生的原因如下:

o    程序访问非法内存地址(如NULL指针)

o    栈溢出

o    大块数据写入到小的buffer内

o    纯虚函数被调用

o    内存不能够被allocate

o    非法参数传入C++系统函数

o    C运行库检测到错误,要求程序退出

SEH handling

C语言处理SEH异常,常用__try{} __except(){}.

C++语言处理SHE异常,用_set_se_traslator()把这个异常转化为C++异常。注意:这个函数工作于每一个线程中。

MSDN 例子

// crt_settrans.cpp
// compile with: /EHa
#include <stdio.h>
#include <windows.h>
#include <eh.h>

void SEFunc();
void trans_func( unsigned int, EXCEPTION_POINTERS* );

class SE_Exception
{

private:
    unsigned int nSE;

public:
    SE_Exception() {}
    SE_Exception( unsigned int n ) : nSE( n ) {}
    ~SE_Exception() {}
    unsigned int getSeNumber() { return nSE; }
};

int main( void )
{
    try
    {
        _set_se_translator( trans_func );
        SEFunc();
    }
    catch( SE_Exception e )
   {
        printf( "Caught a __try exception with SE_Exception.\n" );
    }
}

void SEFunc()
{

    __try
    {
        int x, y=0;
        x = 5 / y;
    }
    __finally
    {
        printf( "In finally\n" );
    }
}

void trans_func( unsigned int u, EXCEPTION_POINTERS* pExp )
{
    printf( "In trans_func.\n" );
    throw SE_Exception();


__try{}__catch(Expression){}缺点在于,用户可能会忘记保证潜在错误code引起的异常,而这个异常不能够被程序捕获。这样的SHE异常需要SetUnhandleExceptionFilter()函数来处理。该函数工作于整个进程。MSDN 例子
LONG WINAPI MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionPtrs)
{

  // Do something, for example generate error report
  //..
  // Execute default exception handler next

  return EXCEPTION_EXECUTE_HANDLER; 
} 

void main()
{ 

  SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
  // .. some unsafe code here 

Note: if someone calls the SetUnhandledExceptionFilter() function after your call, the exception filter will be replaced. This is a disadvantage because you can't chain top-level handlers one above another. If your exception handler function is located inside of a DLL, you should be careful when using the SetUnhandledExceptionFilter() function. If your DLL is unloaded at the moment of crash, the behavior may be unpredictable.

Vectored Exception Handling

VEH作为SHE异常的扩展,由windows XP引入。调用AddVectorExceptionHandler()来添加异常处理函数。

Terminate Handler

当CRT遇到未处理C++类型异常时,会调用terminate()。为了阻止这样调用,可以设置错误处理函数set_terminate()。同样对于unexpected()函数,可以通过set_unexpected()处理该函数。这两个函数均作用于每一个线程。MSDN 例子

void my_terminate_handler()
{
  // Abnormal program termination (terminate() function was called)
  // Do something here
  // Finally, terminate program
  exit(1); 
}

void main()
{

  set_terminate(my_terminate_handler);
  terminate();

Pure Call Handler

使用_set_purecall_handler()函数来处理纯虚函数调用。该函数工作于程序整个进程中。MSDN 例子

// _set_purecall_handler.cpp
// compile with: /W1
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>

class CDerived;

class CBase
{

public:
   CBase(CDerived *derived): m_pDerived(derived) {};
   ~CBase();
   virtual void function(void) = 0;
   CDerived * m_pDerived;
};

class CDerived : public CBase
{

public:
   CDerived() : CBase(this) {};   // C4355
   virtual void function(void) {};
};

CBase::~CBase()
{
   m_pDerived -> function();
}

void myPurecallHandler(void)
{
   printf("In _purecall_handler.");
   exit(0);
}

int _tmain(int argc, _TCHAR* argv[])
{
  _set_purecall_handler(myPurecallHandler);
  CDerived myDerived;


New Operator Fault Handler

使用_set_new_handler()来处理内存分配错误。该函数作用于程序整个进程中。同时采用_set_new_handler()定义对于malloc的错误处理。MSDN 例子

#include <new.h>

int handle_program_memory_depletion( size_t )
{
  // Your code
}

int main( void )
{
   _set_new_handler( handle_program_memory_depletion );
  int *pi = new int[BIG_NUMBER];


Invalid Parameter handler

使用_set_invalid_parameter_handler()函数来处理CRT检测到系统调用中错误参数的case。该函数工作于整个进程中。适用于VS2005之后。MSDN 例子

// crt_set_invalid_parameter_handler.c
// compile with: /Zi /MTd
#include <stdio.h>
#include <stdlib.h>
#include <crtdbg.h>  // For _CrtSetReportMode

void myInvalidParameterHandler(const wchar_t* expression,
   const wchar_t* function, 
   const wchar_t* file, 
   unsigned int line, 
   uintptr_t pReserved)
{
   wprintf(L"Invalid parameter detected in function %s."
            L" File: %s Line: %d\n", function, file, line);
   wprintf(L"Expression: %s\n", expression);
}

int main( )
{

   char* formatString;
   _invalid_parameter_handler oldHandler, newHandler;
   newHandler = myInvalidParameterHandler;
   oldHandler = _set_invalid_parameter_handler(newHandler);
   // Disable the message box for assertions.
   _CrtSetReportMode(_CRT_ASSERT, 0);
   // Call printf_s with invalid parameters.
   formatString = NULL;
   printf(formatString);


Singnal handling

信号是C++提供的程序中断机制,函数signal来处理这些信号。

在VS中,有如下的信号:

  • SIGABRT Abnormal termination
  • SIGFPE Floating-point error
  • SIGILL Illegal instruction
  • SIGINT CTRL+C signal
  • SIGSEGV Illegal storage access
  • SIGTERM Termination request

MSDN说SIGILL,SIGSEGV和SIGTERM,不产生在windows下。但是,实践发现SetUnhandledExceptionFilter()函数代替了SIGSEGV。而_pxcptinfoptrs用来处理SIGFPE。MSDN 例子

void sigabrt_handler(int)
{
  // Caught SIGABRT C++ signal
  // Terminate program
  exit(1);
}

void main()
{
  signal(SIGABRT, sigabrt_handler);
  // Cause abort
  abort();       


 

综上所述,我们给出如下handling函数,来自http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus

void CCrashHandler::SetProcessExceptionHandlers()
{

    // Install top-level SEH handler
    SetUnhandledExceptionFilter(SehHandler);    

     // Catch pure virtual function calls.
    // Because there is one _purecall_handler for the whole process, 
    // calling this function immediately impacts all threads. The last 
    // caller on any thread sets the handler. 
    // http://msdn.microsoft.com/en-us/library/t296ys27.aspx
    _set_purecall_handler(PureCallHandler);    

     // Catch new operator memory allocation exceptions
    _set_new_handler(NewHandler);

     // Catch invalid parameter exceptions.
    _set_invalid_parameter_handler(InvalidParameterHandler); 

     // Set up C++ signal handlers
   _set_abort_behavior(_CALL_REPORTFAULT, _CALL_REPORTFAULT);

 
    // Catch an abnormal program termination
    signal(SIGABRT, SigabrtHandler);  

    // Catch illegal instruction handler
    signal(SIGINT, SigintHandler);     

     // Catch a termination request
    signal(SIGTERM, SigtermHandler);          

}

void CCrashHandler::SetThreadExceptionHandlers()
{
    // Catch terminate() calls. 
    // In a multithreaded environment, terminate functions are maintained 
    // separately for each thread. Each new thread needs to install its own
    // terminate function. Thus, each thread is in charge of its own termination handling.
    // http://msdn.microsoft.com/en-us/library/t6fk7h29.aspx
    set_terminate(TerminateHandler);       


    // Catch unexpected() calls.
    // In a multithreaded environment, unexpected functions are maintained
    // separately for each thread. Each new thread needs to install its own
    // unexpected function. Thus, each thread is in charge of its own unexpected handling.
    // http://msdn.microsoft.com/en-us/library/h46t5b69.aspx  
    set_unexpected(UnexpectedHandler);    

     // Catch a floating point error
    typedef void (*sigh)(int);
    signal(SIGFPE, (sigh)SigfpeHandler);     

    // Catch an illegal instruction
    signal(SIGILL, SigillHandler);     

    // Catch illegal storage access errors
    signal(SIGSEGV, SigsegvHandler);   


 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值