当前位置: 首页 > news >正文

C++ EigenSolver无优化模式下报错分析

记录一次没碰到过的现象:/O2 下正常,/Od 下报错。

问题

void ComputeOptimalRotation(Eigen::Matrix3d& mat_cov3x3, Eigen::Vector4d& quat)
{Eigen::Matrix4d  mat_Eig_R = Eigen::Matrix4d::Zero();{mat_Eig_R(0, 0) = mat_cov3x3(0, 0) + mat_cov3x3(1, 1) + mat_cov3x3(2, 2);mat_Eig_R(0, 1) = mat_cov3x3(1, 2) - mat_cov3x3(2, 1);mat_Eig_R(0, 2) = mat_cov3x3(2, 0) - mat_cov3x3(0, 2);mat_Eig_R(0, 3) = mat_cov3x3(0, 1) - mat_cov3x3(1, 0);mat_Eig_R(1, 0) = mat_cov3x3(1, 2) - mat_cov3x3(2, 1);mat_Eig_R(1, 1) = mat_cov3x3(0, 0) - mat_cov3x3(1, 1) - mat_cov3x3(2, 2);mat_Eig_R(1, 2) = mat_cov3x3(0, 1) + mat_cov3x3(1, 0);mat_Eig_R(1, 3) = mat_cov3x3(2, 0) + mat_cov3x3(0, 2);mat_Eig_R(2, 0) = mat_cov3x3(2, 0) - mat_cov3x3(0, 2);mat_Eig_R(2, 1) = mat_cov3x3(0, 1) + mat_cov3x3(1, 0);mat_Eig_R(2, 2) = -mat_cov3x3(0, 0) + mat_cov3x3(1, 1) - mat_cov3x3(2, 2);mat_Eig_R(2, 3) = mat_cov3x3(1, 2) + mat_cov3x3(2, 1);mat_Eig_R(3, 0) = mat_cov3x3(0, 1) - mat_cov3x3(1, 0);mat_Eig_R(3, 1) = mat_cov3x3(2, 0) + mat_cov3x3(0, 2);mat_Eig_R(3, 2) = mat_cov3x3(1, 2) + mat_cov3x3(2, 1);mat_Eig_R(3, 3) = -mat_cov3x3(0, 0) - mat_cov3x3(1, 1) + mat_cov3x3(2, 2);}Eigen::EigenSolver<Eigen::Matrix4d> es;es.compute(mat_Eig_R);Eigen::Matrix4d mat_EigenValueVec = es.eigenvectors().real();quat[0] = -mat_EigenValueVec(0, 0);quat[1] = mat_EigenValueVec(1, 0);quat[2] = mat_EigenValueVec(2, 0);quat[3] = mat_EigenValueVec(3, 0);
}

以上代码在 /O2 下无报错,但在 /Od 下报错如下:
在这里插入图片描述

0x00007FFB126BC9B4 (xxx.dll) (xxx.exe 中)处有未经处理的异常: 堆栈 Cookie 检测代码检测到基于堆栈的缓冲区溢出。

deepseek 给出的解释:xxx.dll 中发生了基于堆栈的缓冲区溢出,并且被编译器的安全机制(堆栈 Cookie 检测)成功拦截,从而避免了更严重的后果,例如程序被恶意控制或数据损坏。

首先怀疑是未处理矩阵解算失败的情况导致的。(或许解算失败可能会导致es.eigenvectors().real()大小与预料的不一致?)

更改如下:

bool ComputeOptimalRotation(Eigen::Matrix3d& mat_cov3x3, Eigen::Vector4d& quat)
{Eigen::Matrix4d  mat_Eig_R = Eigen::Matrix4d::Zero();{mat_Eig_R(0, 0) = mat_cov3x3(0, 0) + mat_cov3x3(1, 1) + mat_cov3x3(2, 2);mat_Eig_R(0, 1) = mat_cov3x3(1, 2) - mat_cov3x3(2, 1);mat_Eig_R(0, 2) = mat_cov3x3(2, 0) - mat_cov3x3(0, 2);mat_Eig_R(0, 3) = mat_cov3x3(0, 1) - mat_cov3x3(1, 0);mat_Eig_R(1, 0) = mat_cov3x3(1, 2) - mat_cov3x3(2, 1);mat_Eig_R(1, 1) = mat_cov3x3(0, 0) - mat_cov3x3(1, 1) - mat_cov3x3(2, 2);mat_Eig_R(1, 2) = mat_cov3x3(0, 1) + mat_cov3x3(1, 0);mat_Eig_R(1, 3) = mat_cov3x3(2, 0) + mat_cov3x3(0, 2);mat_Eig_R(2, 0) = mat_cov3x3(2, 0) - mat_cov3x3(0, 2);mat_Eig_R(2, 1) = mat_cov3x3(0, 1) + mat_cov3x3(1, 0);mat_Eig_R(2, 2) = -mat_cov3x3(0, 0) + mat_cov3x3(1, 1) - mat_cov3x3(2, 2);mat_Eig_R(2, 3) = mat_cov3x3(1, 2) + mat_cov3x3(2, 1);mat_Eig_R(3, 0) = mat_cov3x3(0, 1) - mat_cov3x3(1, 0);mat_Eig_R(3, 1) = mat_cov3x3(2, 0) + mat_cov3x3(0, 2);mat_Eig_R(3, 2) = mat_cov3x3(1, 2) + mat_cov3x3(2, 1);mat_Eig_R(3, 3) = -mat_cov3x3(0, 0) - mat_cov3x3(1, 1) + mat_cov3x3(2, 2);}Eigen::EigenSolver<Eigen::Matrix4d> es;es.compute(mat_Eig_R);if (es.info() != Eigen::Success || es.eigenvectors().cols() == 0){quat = Eigen::Vector4d(1, 0, 0, 0); return false;}Eigen::Matrix4d mat_EigenValueVec = es.eigenvectors().real();quat[0] = -mat_EigenValueVec(0, 0);quat[1] = mat_EigenValueVec(1, 0);quat[2] = mat_EigenValueVec(2, 0);quat[3] = mat_EigenValueVec(3, 0);return true;
}

此时,在 /Od 下也能无报错运行,但是有意思的是,在解算失败的分支里打上断点时,同样的数据并没有命中该分支中的断点。说明没有遇到解算失败的情况。

分析

	//if (es.info() != Eigen::Success || es.eigenvectors().cols() == 0){//quat = Eigen::Vector4d(1, 0, 0, 0); //return false;}

有意思的来了,上面这个完全不检查外,我尝试了以下N种方式,发现下面这些情况下都不会报错。

	if (es.info() != Eigen::Success || es.eigenvectors().cols() == 0){quat = Eigen::Vector4d(1, 0, 0, 0); return false;}
	if (es.info() != Eigen::Success || es.eigenvectors().cols() == 0){//quat = Eigen::Vector4d(1, 0, 0, 0); //return false;}
	if (es.info() != Eigen::Success /*|| es.eigenvectors().cols() == 0*/){//quat = Eigen::Vector4d(1, 0, 0, 0); //return false;}
	if (/*es.info() != Eigen::Success ||*/ es.eigenvectors().cols() == 0){//quat = Eigen::Vector4d(1, 0, 0, 0); //return false;}
	es.info();//if (es.info() != Eigen::Success || es.eigenvectors().cols() == 0){//quat = Eigen::Vector4d(1, 0, 0, 0); //return false;}
	es.eigenvectors().cols();//es.info();//if (es.info() != Eigen::Success || es.eigenvectors().cols() == 0){//quat = Eigen::Vector4d(1, 0, 0, 0); //return false;}

以下是deepseek的相关分析:
根本原因推测
问题的核心很可能是:EigenSolver 对象在调用 compute 方法后,其内部状态需要某种“触发”才能完全准备好被安全访问。

  1. 状态初始化的必要性:在某些实现(尤其是调试版本)中,仅仅调用 compute 可能不足以完成所有内部数据结构的最终准备。而调用 info() 或 eigenvectors() 这类获取结果的函数,可能会执行一个最终的内部状态提交或验证例程。当存在检查语句时(即使不进入分支),编译器可能会生成代码来评估条件表达式,这个“评估过程”本身可能就隐式地触发了一次完整的内存读写或初始化,从而“歪打正着”地让对象状态变得安全可读。 这有时被称为“加热”(Warming Up)效应。

  2. 调试模式(Od)的敏感性:在关闭优化的调试模式下,编译器不会进行积极的优化,代码执行路径更“字面化”,内存检查(如堆栈 Cookie)也更严格。因此,一个在发布模式下被优化掉的细微未定义行为(比如读取了未初始化的缓存指针),在调试模式下就会暴露为致命的堆栈溢出错误。您的检查语句可能恰好避免了这种细微的未定义行为。

  3. “堆栈缓冲区溢出”的启示:这个错误表明在 EigenSolver 对象内部(或您的代码中),有一个基于堆栈的缓冲区(如固定大小的数组)被写越界了。最可能的原因是:当对象状态未准备好时,eigenvectors() 函数返回的矩阵对象本身或其内部指针是无效的,在对这个无效矩阵调用 .real() 或进行赋值时,发生了非法的内存操作。

解决方案与最佳实践

无意中发现的“进行检查就不报错”恰恰指出了正确的解决方案:必须且应该在访问计算结果前,检查特征求解的状态。

请不要注释掉检查,而是应该保留并完善这个检查逻辑。这是使用类似 Eigen 这样的数学库的良好实践,可以确保程序的健壮性。

总结一下:遇到的这个问题,**根本原因在于 EigenSolver 对象在调试模式下需要一次明确的状态检查(如调用 info())来确保其内部状态完全就绪,然后才能安全访问特征向量。**您观察到的现象不是巧合,而是揭示了库在调试模式下的某种特定行为。因此,保留并重视状态检查是解决此问题的最佳方案。

但是在我的实践中,在N次的调用这个函数过程中,是第M>1次调用时出现的报错, 如果以上推断正确,应在第一次调用时就报错才对。


关于堆栈Cookie

堆栈 Cookie(也称为安全 Cookie 或 Canary)是编译器(如 Microsoft Visual C++ 的 /GS选项)引入的一种重要安全机制,主要用于检测和防止基于堆栈的缓冲区溢出攻击 。下面这个表格概括了其核心工作阶段和要点。

阶段核心任务关键点
程序启动时​​​​初始化全局 Cookie​​生成一个随机值作为全局安全 Cookie (__security_cookie),通常基于高熵源(如系统时间、进程ID)。
​​函数调用时(序言)​​​​植入本地 Cookie​​在存在缓冲区等风险的函数的栈帧中,将全局 Cookie 的一个副本存入返回地址和局部变量之间 。
​​函数返回前(尾声)​​​​验证 Cookie 完整性​​检查栈帧中的本地 Cookie 值是否与全局 Cookie 一致。若不一致,则判定发生溢出,触发错误处理流程(如调用 __report_gsfailure)并终止程序 。

堆栈 Cookie 的局限性
堆栈 Cookie 是有效的缓解措施,但并非万能。它存在一些局限性 :
​​针对性​​:主要防范覆盖返回地址的栈缓冲区溢出,对堆溢出、函数指针覆盖等其他内存破坏攻击无效。
​​可绕过性​​:在特定条件下,如通过信息泄露漏洞获取到 Cookie 值,或者攻击者通过其他手段(如覆盖异常处理程序、函数指针等)在 Cookie 检查前就劫持了程序流程,则可能被绕过 。
​​性能影响​​:虽经优化,但仍会引入微小性能开销。现代编译器会智能判断,通常只为包含缓冲区等敏感操作的函数启用此保护 。

相关编译选项与开发注意
在 ​​MSVC​​ 中,堆栈保护默认通过 /GS编译选项启用。可使用 /GS-显式禁用,但一般不建议这样做 。
开发者应注意,某些操作(如 CRT 库的初始化顺序)可能会影响 Cookie 的正确设置和验证 。

总结
总而言之,堆栈 Cookie 机制如同一位忠实的栈空间卫士,通过“埋设暗记-核对暗记”的方式,有效提升了利用栈缓冲区溢出进行攻击的门槛。它是现代软件纵深防御体系中重要的一环,常与 ASLR(地址空间布局随机化)、DEP(数据执行保护)等其他技术协同工作,共同保障软件安全 。

学到了一些,没完全解惑,浅浅记录一下。


http://www.dtcms.com/a/524280.html

相关文章:

  • 数据结构——折半插入排序
  • io_uring 快吗? Postgres 17 与 18 的基准测试
  • 国产数据库替代MongoDB:政务电子证照新选择
  • 甘孜建设网站集团响应式网站建设
  • 枸杞网站建设方案2024年即将上市的手机
  • Git 版本回退 reset --mixed 命令
  • 博途DWORD中包含word ,字节,位的关系
  • Java Character 类详解
  • 【数据结构】队列“0”基础知识讲解 + 实战演练
  • 【生活】秋冬季节,鼻子很干结痂,扣掉鼻孔干痂流血,鼻塞等护理方法
  • 网站关键词公司百度关键词查询
  • 大模型通识
  • 346. 执行操作后元素的最高频率 I
  • 一些常用的linux操作指令
  • jeecg表单设计器js增强实现效果案例;点按钮出弹框,iframe嵌套,数据传输等
  • Spring IOC源码篇八 核心方法prepareBeanFactory
  • S10--循环队列
  • 基于月尺度水分平衡模型的葡萄园规划与行间管理决策
  • 网站的前期推广网页设计与制作源代码
  • PY32F040单片机介绍(3)
  • 白云网站 建设seo信科上海城市分站seo
  • Python流程控制语法结构-选择分支新特性
  • 快速学完 LeetCode top 1~50 [特殊字符]
  • 河南网站开发培训价格商丘哪里做网站比较好
  • 【常用设计模式全解析】创建型模式(聚焦对象创建机制)、结构型模式(优化类与对象的组合关系)、行为型模式(规范对象间的交互行为)
  • MFF-YOLOv8:基于多尺度特征融合的无人机遥感图像小目标检测
  • SSM框架-MyBatis1
  • 从一开始部署Android项目Sonarqube的自动化扫码+通知+增量扫描功能(Win环境、Docker,基于Jenkins)
  • 对我单位网站进行改版苏州网站建设开发公司
  • 网站架构文案软文推广去哪个平台好