首页 > 代码库 > SEH(structured exception handling)基础篇---终止处理程序

SEH(structured exception handling)基础篇---终止处理程序

前序:最近看SEH看的头晕脑胀/(ㄒoㄒ)/~~,SEH最开始是Windows提供的异常处理机制,只是一个简单的框架,而我们现在使用的SEH都是编译器已经在系统提供的最基础的框架上做了修改的增强版(原始版比较原始,牵扯到大量Windows基础知识,并且需要反汇编看汇编代码来理解。。。。本人现在功力较浅,需要慢慢消化,先看一下增强版,通过C和C++来接触一下。

 

SEH包含两部分功能:终止处理(termination handling)和异常处理(exception handling)。在这先讲一下终止处理程序。

终止程序确保不管一个代码块(被保护代码(the guarded body))是如何推出的,另一个代码块(终止处理程序)总能被调用和执行。

    __try
    {
        //Guarded body
        //...
    }
    __finally
    {
        //Termination handler
        //...
    }

在Guarded body中除非调用ExitProcess,ExitThread,TerminateProcess,TerminateThread来终止进程或线程从而__finally代码块不会被调用,其他情况,终止处理程序都会被调用。

下面通过几个伪代码来理解一下DWORD WhiteLearner_SEH_1(){    DWORD dwTemp;

//等待一个信号
    WaitForSingleObject(__hSem, INFINITE);

    __dwProtectedData = 5;
    dwTemp = __dwProtectedData;
    return dwTemp;
    //信号释放
    ReleaseSemaphore(__hSem, 1, NULL);
    return dwTemp;
}
DWORD WhiteLearner_SEH_2() {
    DWORD dwTemp;
    __try {
        //等待一个信号
        WaitForSingleObject(__hSem, INFINITE);

        __dwProtectedData = 5;
        dwTemp = __dwProtectedData;
        return dwTemp;
    }
    __finally {
        //信号释放
        ReleaseSemaphore(__hSem, 1, NULL);
    }
   dwTemp = 9;
return dwTemp; }

可以看出来,WhiteLearner_SEH_1()中没有用SEH,在ReleaseSemaphore之前便return掉,线程便没有机会释放信号量资源,其他线程当然也不会在得到对这个信号量的控制权。不难想象,在等待同一个信号量的其他线程因此再也没有机会运行,这样的执行顺序带来了很严重的问题。然而在WhiteLearner_SEH_2()中我们运用了__finally,在__try中return之前,__finally会提前运行,__finally代码块中代码运行完成后再次返回到__try代码块中return结束线程。注意,__finally代码块后面的代码没有得到运行便直接return了,返回值为5。

下面更详细具体的解释一下终止处理程序的意义:

 

DWORD WhiteLearner_SEH_3(){
    DWORD dwTemp;
    //等待信号量
    WaitForSingleObject(__hSem, INFINITE);
    dwTemp = Funcinator(__dwProtectedData);
    //释放信号量
    ReleaseSemaphore(__hSem, 1, NULL);
    return dwTemp;
}

 

这个函数中释放前进行了一系列操作Funcinator,如果操作中存在缺陷导致程序非法访问内存,则会导致Windows错误报告(Windows Error Reporting,WER)弹出对话框:“Application has stopped working”。如果用户取消对话框,则进程直接终止,也就是说信号量没有来的及释放,跟WhiteLearner_SEH_1函数类似。

还有,__finally代码块是程序顺序运行也会执行的代码,并且只要__try代码块没有正常运行结束,__finally代码块就会插入__try中运行。(忽略栈耗尽异常)__finally代码块运行的第三种情况--全局展开,这个在SEH下一部分异常处理再详细介绍。

DWORD WhiteLearner_SEH_4() {
    DWORD dwTemp = 0;
    while (dwTemp < 10)
    {
        __try {
            if (dwTemp == 2)
                continue;
            if (dwTemp == 3)
                break;
        }
        __finally {
            dwTemp++;
        }
        dwTemp++;
    }
    return dwTemp;
}

这个函数的返回值是4。具体过程希望读者自己思考。

最后,终止处理程序也可以进行最后所有的清理工作:

技术分享
DWORD WhiteLearner_SEH_5() {
    HANDLE hFile = INVALID_HANDLE_VALUE;
    PVOID  pvBuf = NULL;
    BOOL   bFunctionOk = FALSE;
    __try {
        DWORD dwNumBytesRead;
        BOOL  IsOk;
        hFile = CreateFile(TEXT("SOMEDATA>DAT"), GENERIC_READ, FILE_SHARE_READ, NULL, 
            OPEN_EXISTING, 0, NULL);
        if (hFile == INVALID_HANDLE_VALUE){
            //进入__finally
            __leave;
        }

        pvBuf = VirtualAlloc(NULL,  0x1000, MEM_COMMIT, PAGE_READWRITE);
        if (pvBuf == NULL) {
            __leave;
        }
        IsOk = ReadFile(hFile, pvBuf, 0x1000, &dwNumBytesRead, NULL);
        if (!IsOk || dwNumBytesRead == 0) {
            __leave;
        }
        bFunctionOk = TRUE;
    }
    __finally {
        if (pvBuf != NULL) {
            VirtualFree(pvBuf, MEM_RELEASE | MEM_DECOMMIT);
        }
        if (hFile != INVALID_HANDLE_VALUE)
        {
            CloseHandle(hFile);
        }
    }
    return(bFunctionOk);
}
View Code

通过这次介绍大家应该能感受到终止处理程序的强大功能,总结一下有下面几条:

1.因为清理工作集中在一个地方执行,并且保证能得到执行,从而简化了错误处理。

2.提高了代码的可读性。

3.让代码更容易维护。

4.如果正常使用,他们对程序性能和体积的影响是微小的。

感谢大家阅读,本人现在也在黑暗中摸索前进,欢迎互相讨论,互相学习。

 

参考资料:《WINDOWS核心编程》

           大神博客http://www.cnblogs.com/lanrenxinxin/p/4631836.html#3340777

 

SEH(structured exception handling)基础篇---终止处理程序