veh注册后仍收不到非法内存访问异常,因其按线程注册且仅捕获本线程异常;多线程需各线程单独调用addvectoredexceptionhandler(1, handler),并注意优先级、地址验证及栈展开限制。

VEH注册后为什么仍然收不到非法内存访问异常
因为VEH是按线程注册的,且默认只捕获当前线程触发的异常;如果非法访问发生在其他线程(比如DLL加载时的静态构造函数、第三方库线程池、异步I/O回调),VEH不会自动生效。另外,SetThreadExceptionFilter 并不存在——正确函数是 AddVectoredExceptionHandler,第一个参数为 1 表示前置处理(优先于SEH),0 表示后置(常被忽略)。
常见错误现象:Access violation reading location 0x00000000 直接弹Windows错误框,VEH回调函数根本没执行。
- 确保在目标线程上下文中调用
AddVectoredExceptionHandler(1, YourHandler),多线程场景下每个线程都要单独注册 - 不要依赖主线程注册来覆盖工作线程——线程局部存储(TLS)和VEH作用域完全独立
- 检查是否被更高优先级的VEH拦截(如某些反作弊/调试工具会抢注前置VEH并吞掉异常)
VEH Handler里如何安全判断是否为非法内存访问
不能只看 EXCEPTION_ACCESS_VIOLATION,必须结合 ExceptionRecord->ExceptionInformation[0](操作类型)和 ExceptionRecord->ExceptionInformation[1](出错地址),否则可能误判合法的硬件断点或数据对齐异常。
典型误判场景:MMX/SSE指令引发的 EXCEPTION_DATATYPE_MISALIGNMENT 被当成内存访问错误;或 EXCEPTION_BREAKPOINT 来自调试器单步,不该被“捕获并吞掉”。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 先校验
ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION - 再检查
ExceptionInfo->ExceptionRecord->ExceptionInformation[0]:0=读,1=写,8=执行(DEP违例) - 用
IsBadReadPtr或VirtualQuery验证地址合法性前,必须确保该地址在当前进程空间内——跨进程指针会导致VirtualQuery返回0
捕获后能否“修复”并继续执行(例如模拟空指针安全解引用)
可以,但仅限于读操作且目标地址可映射为有效内存;写操作和执行违例基本无法安全恢复。Windows不允许在VEH中修改 CONTEXT 的 Eip/Rip 后直接返回——必须调用 RaiseException 或让系统继续分发到SEH链,否则线程状态不一致。
真实限制:即使你把0地址映射为一页可读内存(VirtualAlloc(0, ..., PAGE_READWRITE)),后续任意线程对该地址的写入仍会触发新异常,且无法保证原子性。
- 读违例可临时
VirtualAlloc(0, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READONLY)模拟空指针容忍(仅调试用途) - 写违例几乎无法安全恢复——除非你精确知道哪个变量被野指针写,并能重定向其地址(需配合页保护+写时复制,成本远超收益)
- 绝对不要在VEH里调用
malloc、std::string构造或任何可能触发新异常的C++运行时函数
与SEH混用时VEH的优先级和栈展开行为
VEH总是在SEH之前被调用,但VEH handler返回 EXCEPTION_CONTINUE_SEARCH 才会继续走SEH;返回 EXCEPTION_EXECUTE_HANDLER 会终止异常分发,且**不触发栈展开(unwind)**——这意味着所有 __try/__finally 或 C++ 析构函数都不会执行。
后果很实际:如果某个对象持有文件句柄或内存池锁,在VEH里“吃掉”异常后,资源永久泄漏;而SEH的 __finally 块本该释放它们。
- 需要栈展开 → 必须返回
EXCEPTION_CONTINUE_SEARCH,让SEH接手 - 想记录日志+继续崩溃 → VEH里记录,然后返回
EXCEPTION_CONTINUE_SEARCH - 想热修复(如跳过某条指令)→ 修改
CONTEXT->Eip后返回EXCEPTION_CONTINUE_EXECUTION,但必须确保跳转后代码不依赖已破坏的寄存器或栈
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










