VS编译器优化诱发一个的Bug

Bug的背景

我正在把某个C++下的驱动程序移植到C下,前几天发生了一个比较诡异的问题。

驱动程序有一个bug,但是这个bug只能 Win32 Release 版本下的驱动才能重现。在 Win32 Debug 版本下,和 Win64 Release/Debug 版本下均无法重新。

随着一步步的分析,最终发现问题是由于VS编译器的一个优化诱发的。当然这并不是VS编译器的bug,只是由于优化诱发程序里面的某个bug.

调试的思路

1. Debug Vs Release

首先想到的自然是看看Debug版本和Release版本运行是有啥区别了。Release版本本质上和Debug版本没啥区别,一样都可以使用调试器调试,只不过有些大大小小需要注意的地方罢了。基本上熟知编译器的优化原理和调试器,调试Release版本的程序也不是啥困难的事情。

一般导致Debug和Release不同的常见问题无非下面这些,未初始化的局部变量,程序指针访问越界,多线程同步问题。而这些问题都是很容易发现的,但随着调试的深入,并没有发现这些问题的踪迹,反而所有的代码都工作的很好,没啥异常发生。对比Debug和Release版本下的流程,Release版本的问题在于在某个时候硬件没有如期的触发中断。但在这之前两个版本所执行的代码逻辑完全一样,没有啥区别。

问题越发诡异了。

2. 32bit Vs 64 bit

既然64bit Release的版本没有问题,但32bit Release有问题,这也是一个突破的思路。

把相关的代码拿出来仔细梳理,注意看一些32/64bit下的常见问题,诸如指针大小,整数溢出等问题。不过依然没有发现问题。

3. 编译器的优化

Debug和Release的最大的区别自然是编译器的优化不同,但是哪个编译器不是久经考验,要是说编译器上出问题,那真是撞了大运了,所以没有第一时间考虑是由于优化造成的。不过既然直接调试代码没发现问题的所在,那只有使用另外一种分析方法了,那就是不断缩小导致问题的范围。

既然我手上有两个版本,一个好的,一个坏的。那只要不断缩小两个版本之间的不同,最终就能定位到导致问题的部分。

所以第一个拿来开刀的自然是编译器的优化选项。几经尝试,终于发现诱发问题的编译器优化是这一项,Favor Size Or Speed. 诡异,真是相当的诡异呀。不过无所谓,既然找到了这一个线索,下面就好找了。这个优化只是一个函数内的局部优化,只要针对不同的函数分别打开和关闭这个优化,自然就能发现问题所在了。

问题的根源

针对一些可疑的代码,分别打开和关闭这个Favor Size Or Speed的优化,不断的缩小范围之后,最终定位到某个函数是罪魁祸首。然后比较了一下生成的汇编代码,最后定位到了下面这行语句

pDevice->pReg->S = 0xFFFFFFFF;

而这行代码生成的汇编代码如下:

or      dword ptr [eax+10h],0FFFFFFFFh   //Release版本,Favor Size优化
mov dword ptr [eax+10h],0FFFFFFFFh //Debug版本,无优化

乍一看一定会觉得这个诡异,因为or和mov指令在这里的逻辑其实是一模一样的,编译器没有任何错误。那为何会有不同的执行效果呢?

其实原因在于pDevice->pReg->S并不是一个普通的内存地址,他是一个MMIO(memory mapped IO) address地址。也就是说这个变量并不存在于内存里面,而是硬件的某个寄存器,只不过和内存共用了一个地址空间。而对于这种MMIO address,虽然可以直接象访问普通内存一样读写他们,但最安全的方式还是使用Windows提供的函数,所以对于这个bug的修复是

WRITE_REGISTER_ULONG(&pDevice->pReg->S,0xFFFFFFFF);

至于为啥会出这种乌龙,其实就是一开始移植的时候粗心大意了。pDevice->pReg->S = 0xFFFFFFFF; 这句C++语句中的=其实一个重载过的C++运算符,内部的实现就是WRITE_REGISTER_ULONG,移植过来的时候也没有细看具体哪个S是个什么东西,就抄过来了

VS编译器优化诱发一个的Bug的更多相关文章

  1. 【转】C 编译器优化过程中的 Bug

    C 编译器优化过程中的 Bug 一个朋友向我指出一个最近他们发现的 GCC 编译器优化过程(加上 -O3 选项)里的 bug,导致他们的产品出现非常诡异的行为.这使我想起以前见过的一个 GCC bug ...

  2. 探索c#之尾递归编译器优化

    阅读目录: 递归运用 尾递归优化 编译器优化 递归运用 一个函数直接或间接的调用自身,这个函数即可叫做递归函数. 递归主要功能是把问题转换成较小规模的子问题,以子问题的解去逐渐逼近最终结果. 递归最重 ...

  3. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part6:Move语义和编译器优化

    本文为第六部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...

  4. gcc编译器优化给我们带来的麻烦???

    gcc编译器优化给我们带来的麻烦??? 今天看到一个很有趣的程序,如下: ? 1 2 3 4 5 6 7 8 9 int main() {     const int a = 1;     int * ...

  5. C#编译器优化那点事

    使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的. 优化代码开关即optimize开 ...

  6. C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理

    C#编译器优化那点事   使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的.优化代码 ...

  7. C#编译器优化

    C#编译器优化 https://www.cnblogs.com/podolski/p/8987595.html 使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置 ...

  8. js动画--一个小bug处理下

    对于上面的课程我们很好的处理了一个小bug,那么我们现在讲程序进行优化一下,前一节的程序中,我们处理处理的属性都是写死了的.为了我们能够很好的对某个属性进行操作的话.我们这样来设置. js文件 win ...

  9. 2018-8-10-win10-uwp-禁止编译器优化代码

    title author date CreateTime categories win10 uwp 禁止编译器优化代码 lindexi 2018-08-10 19:16:50 +0800 2018-2 ...

随机推荐

  1. js:插入节点appendChild insertBefore使用方法

    首先 从定义来理解 这两个方法: appendChild() 方法:可向节点的子节点列表的末尾添加新的子节点.语法:appendChild(newchild) insertBefore() 方法:可在 ...

  2. 华为S5700S-52P-LI-AC千兆网管交换机web登录界面配置

    研究一下午,包装附的说明书根本就是错误的,通过技术售后和官方的文档结合,总算可以登录交换机的web管理界面. 首先需要使用通讯控制线缆(包装中附)连接电脑和交换机,一头接交换机的Console口,一头 ...

  3. LinkedHashMap及其源码分析

    以下内容基于jdk1.7.0_79源码: 什么是LinkedHashMap 继承自HashMap,一个有序的Map接口实现,这里的有序指的是元素可以按插入顺序或访问顺序排列: LinkedHashMa ...

  4. knockoutjs with绑定导致unobtrusive validation失效的问题

    如果最初的时候with绑定的对象是空的,那么with绑定内部的unobtrusive validation规则在提交的时候无法生效,无法进行验证. 解决办法: 在提交的时候(或者with绑定的对象非空 ...

  5. ORACLE 查看RMAN的备份信息总结

    关于Oracle数据库的RMAN备份,除了邮件外,是否能通过其它方式检查RMAN备份的成功与失败呢?其实我们可以通过下面SQL脚本来检查某个时间段备份失败的记录: SELECT * FROM V$RM ...

  6. SQL Server ---(CDC)监控表数据(转译)

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 实现过程(Realization) 补充说明(Addon) 参考文献(References) ...

  7. MySQL-procedure(loop,repeat)

    在 MySQL-procedure(cursor,loop) 中将spam_keyword表中的文字全部分割到t表当中,且每一行的字都不重复,那t表可以用来当作一个小字典,只有1000来个字符,这次把 ...

  8. iOS基于MBProgressHUD的二次封装,一行搞定,使用超简单

    MBProgressHUD的使用,临时总结了几款最常用的使用场景: 1.提示消息 用法: [YJProgressHUD showMessage:@"显示文字,1s隐藏" inVie ...

  9. x01.Excel: 合计件数

    由于 VBA 与 Excel 是耦合的,所以还是先看表: 件数的计算,用 Mod 即可.但考虑到要求码洋.数量等多种需求,就该 VBA 登场了.代码如下: '===================== ...

  10. 2016-2017 CT S03E07: Codeforces Trainings Season 3 Episode 7 - HackerEarth Problems Compilation

    B: 思路: 暴力,每两个判断一下; C: 思路: 容斥定理,先枚举脖子下面那个点和那个不可描述的点,算出所有的方案数,这里面有多的腿当成了脖子或者胳膊的,然后就再枚举这种情况把这些减去,又减多了; ...