Windows SEH异常处理讨论

Windows C++程序异常的类型

在Windows C++异常的场景中,我们需要理解以下两种类型的异常:

  1. C++语言抛出的异常。
    • 这是利用C++ throw抛出的exception,利用C++ try-catch即可捕获。
    • 即便是来自于另一个DLL的C++ exception,仍然能利用C++ try-catch捕获。
  2. 访问操作系统受保护内存导致的异常。
    • 利用Windows API函数SetUnhandledExceptionFilter()可捕获。
    • 利用C++ try-catch无法捕获。

试验与分析

C++语言抛出的异常

即用C++ throw关键字抛出的C++ exception,则利用C++ try-catch即能捕获。已用如下样例代码证明:

// This is the main program, which links to DLL1
// main.cpp#include <iostream>int main()
{try{ThrowCppException();}catch (std::exception& e){std::cout << e.what() << "\n";}std::cout << "Program finished normally\n";return 0;
}
// DLL1, this is a Dynamic Link Library(DLL)
// DLLTest.h
#pragma once
#if defined(DLL1_EXPORTS)
#define DLL1_SYMBOL_EXPORT __declspec(dllexport)
#else
#define DLL1_SYMBOL_EXPORT __declspec(dllimport)
#endif DLL1_SYMBOL_EXPORT void ThrowCppException();
// DLL1, this is a Dynamic Link Library(DLL)
// DLLTest.cpp
#include "DLLTest.h"
#include <exception>void ThrowCppException()
{throw std::exception("This is an C++ exception");
}

输出如下:

This is an C++ exception
Program finished normally...\ConsoleApplication2\x64\Debug\ConsoleApplication2.exe (process 52160) exited with code 0.
Press any key to close this window . . . 

程序可以对C++异常进行处理,然后再继续正常地运行,或者正常地退出。

内存访问异常

首先,我们来证明,这类异常是无法通过C++ try-catch捕获的。已用如下样例代码证明:

// This is the main program, which links to DLL1
// main.cpp#include <iostream>int main()
{try{WriteOSProtectedMemory();}catch (std::exception& e){std::cout << e.what() << "\n";}std::cout << "Program finished normally\n";return 0;
}
// DLL1, this is a Dynamic Link Library(DLL)
// DLLTest.h
#pragma once
#if defined(DLL1_EXPORTS)
#define DLL1_SYMBOL_EXPORT __declspec(dllexport)
#else
#define DLL1_SYMBOL_EXPORT __declspec(dllimport)
#endif DLL1_SYMBOL_EXPORT void ThrowCppException();
// DLL1, this is a Dynamic Link Library(DLL)
// DLLTest.cpp
#include "DLLTest.h"
#include <exception>void ThrowCppException()
{throw std::exception("This is an C++ exception");
}

输出如下:

...\ConsoleApplication2\x64\Debug\ConsoleApplication2.exe (process 39044) exited with code -1073741819.
Press any key to close this window . . .

程序直接退出了,没有输出"Program finished normally"。另外,输出"exited with code -1073741819",意味着程序不是正常地结束。

应用层捕获DLL层的内存访问异常

应用层利用Windows API函数SetUnhandledExceptionFilter(),可对DLL层触发的内存访问异常进行捕获。已用以下样例代码证明:

#include "DLLTest.h"#include <iostream>
#include <Windows.h>// 试图在App层面捕获全部OS Exception
LONG NTAPI OSExceptionHandlerInApp(EXCEPTION_POINTERS* pExcepInfo)
{// Do something, for example save the data to local diskstd::cout << "OSExceptionHandlerInApp: SEH handler in App caught unhandled exception\n";std::cout << "Program could not finish normally\n";return EXCEPTION_EXECUTE_HANDLER;
}int main()
{SetUnhandledExceptionFilter(OSExceptionHandlerInApp);WriteOSProtectedMemory();std::cout << "Program finished normally\n";return 0;
}
// DLL1, this is a Dynamic Link Library(DLL)
// DLLTest.h
#pragma once#if defined(DLL1_EXPORTS)
#define DLL1_SYMBOL_EXPORT __declspec(dllexport)
#else
#define DLL1_SYMBOL_EXPORT __declspec(dllimport)
#endifDLL1_SYMBOL_EXPORT void WriteOSProtectedMemory();
// DLL1, this is a Dynamic Link Library(DLL)
// DLLTest.cpp
#include "DLLTest.h"void WriteOSProtectedMemory()
{char* p = (char*)0x0000000000000078;*p = 32;
}

输出如下:

OSExceptionHandlerInApp: SEH handler in App caught unhandled exception
Program could not finish normally...\ConsoleApplication2\x64\Debug\ConsoleApplication2.exe (process 38176) exited with code -1073741819.
Press any key to close this window . . . 

可以看出,应用层利用ExceptionHander捕获了DLL触发的内存异常,然后程序退出。

DLL层调用SetUnhandledExceptionFilter()导致应用层无法捕获内存异常

如果DLL层调用了SetUnhandledExceptionFilter(),则导致应用层调用SetUnhandledExceptionFilter()无效。实际上,是DLL层把应用层注册的ExceptionFilter改写了。已用以下样例代码证明:

#include "DLLTest.h"#include <iostream>
#include <Windows.h>// 试图在App层面捕获全部OS Exception
LONG NTAPI OSExceptionHandlerInApp(EXCEPTION_POINTERS* pExcepInfo)
{// Do something, for example save the data to local diskstd::cout << "OSExceptionHandlerInApp: SEH handler in App caught unhandled exception\n";std::cout << "Program could not finish normally\n";return EXCEPTION_EXECUTE_HANDLER;
}int main()
{SetUnhandledExceptionFilter(OSExceptionHandlerInApp);OverwriteOSExceptionHander();WriteOSProtectedMemory();std::cout << "Program finished normally\n";
}
// DLL1, this is a Dynamic Link Library(DLL)
// DLLTest.h
#pragma once#if defined(DLL1_EXPORTS)
#define DLL1_SYMBOL_EXPORT __declspec(dllexport)
#else
#define DLL1_SYMBOL_EXPORT __declspec(dllimport)
#endifDLL1_SYMBOL_EXPORT void WriteOSProtectedMemory();
// DLL1, this is a Dynamic Link Library(DLL)
// DLLTest.cpp
#include "DLLTest.h"
#include <iostream>
#include <Windows.h>void WriteOSProtectedMemory()
{char* p = (char*)0x0000000000000078;*p = 32;
}// 在DLL中截获OS Exception
LONG NTAPI OSExceptionHandlerInDLL(EXCEPTION_POINTERS* pExcepInfo)
{std::cout << "OSExceptionHandlerInDLL: SEH handler in DLL caught unhandled exception\n";return EXCEPTION_EXECUTE_HANDLER;
}void OverwriteOSExceptionHander()
{SetUnhandledExceptionFilter(OSExceptionHandlerInDLL);
}

输出如下:

OSExceptionHandlerInDLL: SEH handler in DLL caught unhandled exception...\ConsoleApplication2\x64\Debug\ConsoleApplication2.exe (process 20108) exited with code -1073741819.
Press any key to close this window . . .

可以看出,应用层已经无法利用ExceptionHander捕获DLL触发的内存异常,直接退出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/58945.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows 基础(一):深入理解Windows,掌握命令行与Shell

内容预览 ≧∀≦ゞ Windows 基础&#xff08;一&#xff09;声明导语一、Windows 和 Linux 的区别二、Windows 的ShellShell 和 终端 的区别1. 命令提示符&#xff08;CMD&#xff09;2. Windows PowerShell3. Windows Terminal4. Windows Subsystem for Linux (WSL) 三、Windo…

【数据库系统概论】第3章 关系数据库标准语言SQL(一)数据查询(超详细)

目录 一、单表查询 1. 简单的数据查询 &#xff08;1&#xff09;选择表中若干列 &#xff08;2&#xff09;选择表中若干行&#xff08;元祖&#xff09; 2. 聚合函数与分组查询 聚集函数 GROUP BY分组查询 二、联接查询 1、连接概述 2. 内联接&#xff08;INNER JO…

unity后端kbengine用DOTween让 移动同步丝滑

unity在网络同步kbengine框架,同步移动时, 看自己很丝滑,但看他人是在跳越移动,一闪一闪,像掉帧, 看什么插值,高频同步,都不实用 用DOTween的 transform.DOMove(目标位置, 时间); //顺滑移动动画 这段代码不是放在Avatar.cs,放在AvatarView.cs里 if (Avatar.isPlayer() false…

【Effective C++】阅读笔记3

1. 成员变量声明为Private 建议将成员变量声明为Private&#xff0c;然后再public中提供调用该数据的接口 设置成Private的原因分析 类内成员变量被声明为Private&#xff0c;那么就可以外部代码直接访问或者修改内部数据通过公共接口获取内部数据&#xff0c;这样可以减少对外…

CSS3新增背景属性(四)

CSS3新增背景属性 1 background-origin 设置背景图原点起始位置&#xff1a; padding-box&#xff1a;默认值从padding区域开始显示背景图像&#xff1b;border-box&#xff1a;从border区域开始显示背景图像&#xff1b;content-box&#xff1a;从content区域开始显示背景图像…

C语言中的main函数:命令行参数的工作原理

在C语言中&#xff0c;main函数是程序的入口点。它不仅可以接受返回值&#xff0c;还能处理命令行参数&#xff0c;允许用户在运行程序时传递数据。命令行参数是用户在启动程序时通过命令行界面提供的输入。C语言允许通过main函数的参数来访问这些输入。   int main(int argc…

我在命令行下学日语

同一个动作重复 300 遍&#xff0c;肌肉就会有记忆&#xff0c;重复 600 遍&#xff0c;脊柱就会有记忆&#xff0c;学完五十音图不熟练&#xff0c;经常遗忘或者要好几秒才想得起来一个怎么办&#xff1f;没关系&#xff0c;我做了个命令行下的小游戏 KanaQuiz 来帮助你记忆&a…

c++:vector

一、vector是什么&#xff1f; 1.1 vector的介绍 vector是表示可变大小数组的序列容器。 就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是…

一键切换暗黑模式,这些代码片段你不可错过

文章目录 前言正文1.多主题切换2.使用 SASS 实现轻松深色模式3.动画切换浅色与深色模式4.纯 CSS 主题切换5.GitHub 风格的深色模式切换6.持久深色模式7.基本 Vue 响应式切换8.创意灯泡切换 总结 前言 如今&#xff0c;许多网站设计师都会为用户提供浅色和深色模式的选择。这不…

理解为什么要有C++设计模式

什么时设计模式&#xff1f; 每一个模式描述了一个在我们周围不断重复的问题以及该问题的解决方案的核心&#xff0c;这样&#xff0c;就能一次有一次地使用该方案&#xff0c;而不必做重复劳动。 如何解决复杂性&#xff1f; 分解&#xff1a;人们面对复杂性有一个常见的做法…

HJ33 整数与IP地址间的转换

HJ33 整数与IP地址间的转换 整数与IP地址间的转换 描述 原理&#xff1a;ip地址的每段可以看成是一个0-255的整数&#xff0c;把每段拆分成一个二进制形式组合起来&#xff0c;然后把这个二进制数转变成 一个长整数。 举例&#xff1a;一个ip地址为10.0.3.193 每段数字 …

雷军救WPS“三次”,WPS注入新生力量,不再“抄袭”微软

救WPS“三次” 1989年&#xff0c;求伯君用128万行代码编写出了WPS1.0&#xff0c;宣告了中国自主办公时代的开启。 那时候&#xff0c;雷军还在武汉大学深造&#xff0c;他早就把求伯君当成了自己的榜样&#xff0c;这一来二去的&#xff0c;雷军和WPS之间也就结下了不解之缘…

[MySQL#10] 索引底层(1) | Page | 页目录

目录 1. 初识索引 2. 认识磁盘 3. MySQL与磁盘交互基本单位 4. 索引的理解 1. 重谈Page 2. 为什么IO交互要用Page 3. 有主键的表插入数据时的排序 4. 单个Page与多个Page 4.1 单个Page 4.2 多个Page 目录 单Page目录 多Page目录 在看本文之前&#xff0c;可以回顾…

sklearn 实现随机森林分类器 - python 实现

python sklearn 实现随机森林分类器 from sklearn.ensemble import RandomForestClassifier from sklearn.datasets import load_iris # 加载数据集 irisload_iris() x,yiris.data,iris.target print("x y shape:",x.shape,y.shape) # 创建并训练模型 model Random…

Altium Designer使用技巧(二)

一、创建类 1、按DC键&#xff0c;打开对象类。 2、右键添加一个类。命名为PWR。 3、将所有的电源类&#xff0c;全部添加到新创建的类中&#xff0c;从非成员类中点选到成员类中。 4、右下角点panes ,点PCB。 5、然后在左边单击PWR&#xff0c;点连接&#xff0c;可显示或…

<十六>Ceph mon 运维

Ceph 集群有故障了&#xff0c;你执行的第一个运维命令是什么&#xff1f; 我猜测是ceph -s 。无论执行的第一个命令是什么&#xff0c;都肯定是先检查Mon。 在开始之前我们有必要介绍下Paxos协议&#xff0c;毕竟Mon就是靠它来实现数据唯一性。 一&#xff1a; Paxos 协议 1…

Python Flask 数据库开发

Python Flask 数据库开发 引言环境配置创建 Flask 应用&#xff0c;连接数据库定义路由定义模型创建表创建 API 数据库直接操作启动 Flask 应用app.py 示例运行 Flask访问应用 展望 引言 在现代 web 开发中&#xff0c;Python 的 Flask 框架因其轻量和灵活性受到广泛欢迎。结合…

NPOI 操作详解(操作Excel)

目录 1. 安装 NPOI 2. 使用 NPOI 创建新 Excel 文件 3. 设置列宽和行高 1. 设置列宽 2. 设置行高 3. 同时设置列宽和行高 4. 设置统一的行高 5. 设置统一的列宽 6. 应用统一的行高和列宽 4. 合并单元格 5. 设置单元格样式&#xff08;字体、边框、背景色等&#xf…

TCP/IP网络编程:理解网络编程和套接字

TCP/IP网络编程&#xff1a;理解网络编程和套接字 网络编程又叫做套接字编程&#xff0c;是因为在网络编程中依赖使用套接字(socket),网络编程一般是C/S架构&#xff0c;即客户端/服务器模式&#xff0c;在服务器端依赖套接字绑定自身接口&#xff0c;并开启监听客户端连接&am…

Spring中lazy-init属性

Spring中lazy-init属性 1. 在 Spring 框架中的 lazy-init 属性 在 Spring 框架中&#xff0c;lazy-init 属性主要用于控制 Spring 容器中 Bean 的初始化时机。 含义&#xff1a; 当一个 Bean 被定义在 Spring 的配置文件&#xff08;可以是 XML 配置或者基于注解的配置等效场景…