《Windows核心编程》读书笔记二十四章 异常处理程序与软件异常

第24章 异常处理程序与软件异常


本章内容

24.1 通过实例理解异常过滤程序和异常处理程序

24.2 EXCEPTION_EXECUTE_HANDLER

24.3 EXCEPTION_CONTINUE_EXECUTION

24.4 EXCEPTION_CONTINUE_SEARCH

24.5 GetExceptionCode

24.6 GetExceptionInformation

24.7 软件异常


除0或者访问NULL地址,会被cpu捕获。称为硬件异常

操作系统和应用程序也可以自行抛出异常,称为软件异常。

一个异常处理程序的语法结构

	__try{
		// Guarded body
	}
	__except (exception filter) {
		// Exception handler
	}


__except块不能和__finally块同时存在。但是可以嵌套存在


24.1 通过实例理解异常过滤程序和异常处理程序

24.1.1 Funcmeister1 函数

	DWORD dwTemp;
	// 1. Do any processing here.
	//...
	__try {
		// 2. Perform some operation.
		dwTemp = 0;
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		// Handle an exception; this never execute.
		// ...

	}

	// 3. Continue processing.
	return dwTemp;
}

这个函数不会导致异常,在异常处理程序的try块中可以使用return goto continue和break。因为这些语句不会带来局部展开的开销。


24.1.2 Funcmeister2 函数

DWORD Funcmeister2() {
	DWORD dwTemp = 0;
	// 1. Do any processing here.
	//...
	__try {
		// 2. Perform some operation.
		dwTemp = 5 / dwTemp;		// Generates an exception
		dwTemp += 10;				// Never executes
	}
	__except (/* 3. Evaluate filter. */EXCEPTION_EXECUTE_HANDLER) {
		// 4. Handle an exception;
		MessageBeep(0);
		// ...
	}

	// 5. Continue processing.
	return dwTemp;
}

除零错误会被cpu捕获并抛出一个硬件异常。接着系统定位到except块,并对异常过滤程序的表达式求值。
可能是一下3个值



异常处理的过程:


24.2 EXCEPTION_EXECUTE_HANDLER

异常处理完毕以后,从哪里开始继续执行代码?
1. 可能是导致异常的那条cpu指令之后的第一条指令开始执行。可能导致连锁异常
2. 从产生异常的那条指令本身开始执行。( EXCEPTION_CONTINUE_EXECUTION
3. 从except块后的第一句代码继续(实际情况如此)

24.2.1 一些有用的例子

一个不恰当的try/except
char* RobustStrCpy(char* strDes, const char* src) {
	__try {
		strcpy(strDes, src);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		// Nothing to do here.
	}

	return strDes;
}
以上代码虽然捕获了异常但是没有做任何处理。这是不可取的。可能会导致隐患和后续问题。


原则:只处理我们知道怎么处理的异常,并且也不要忘记其他的保护措施。以防止程序状态混乱或者安全漏洞。

一个健壮异常处理的例子。
int RobustHowManyToken(const char * str) {
	int nHowManyTokens = -1; // -1 indicates failure
	char * strTemp = NULL;	// Assume failure

	__try {
		// Allocate a temporary buffer
		strTemp = (char*)malloc(strlen(str) + 1);

		// Copy the original string to the temporary buffer
		strcpy(strTemp, str);

		// Get the first token
		char * pszToken = strtok(strTemp, " ");

		// Iterate through all the tokens
		for (; pszToken != NULL; pszToken = strtok(NULL, " "))
			nHowManyTokens++;

		nHowManyTokens++;		// Add 1 since we started at -1
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		// Nothing to do here
	}

	// Free the temporary buffer (guaranteed)
	free(strTemp);
	return (nHowManyTokens);
}

能过处理常见的内存错误。

另一个内存拷贝例子
PBYTE RobustMemDup(PBYTE pbSrc, size_t cb) {

	PBYTE pbDup = NULL;		// Assume failure

	__try {

		// Allocate a buffer for the duplicate memory block
		pbDup = (PBYTE)malloc(cb);

		memcpy(pbDup, pbSrc, cb);
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
		free(pbDup);
		pbDup = NULL;
	}

	return pbDup;
}


24.2.2 全局展开

当异常过滤程序的计算结果为 EXCEPTION_EXECUTE_HANDLER时,系统必须执行全局展开(unwind)。
全局展开导致所有已经开始执行但尚未完成的try-finally块得以继续执行,在调用栈中,这些try-finally块位于对异常进行处理的try-except块下方(Call stack窗口中下方就是趋向栈底的函数)。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值