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. 各类 HTTP 返回状态代码详解

    完整版 1**(信息类):表示接收到请求并且继续处理 100——客户必须继续发出请求 101——客户要求服务器根据请求转换HTTP协议版本 2**(响应成功):表示动作被成功接收.理解和接受 200— ...

  2. 让UNION与ORDER BY并存于SQL语句当中

    在SQL语句中,UNION关键字多用来将并列的多组查询结果(表)合并成一个结果(表),简单实例如下: SELECT [Id],[Name],[Comment] FROM [Product1] UNIO ...

  3. Sql Server之旅——第四站 你必须知道的非聚集索引扫描

    非聚集索引,这个是大家都非常熟悉的一个东西,有时候我们由于业务原因,sql写的非常复杂,需要join很多张表,然后就泪流满面了...这时候就 有DBA或者资深的开发给你看这个猥琐的sql,通过执行计划 ...

  4. mysql-2 mysql客户端

    mysql 官方客户端  MySQL-Workbench 下载链接http://dev.mysql.com/downloads/workbench/ 具体安装步骤就不写了,直接一直下一步就可以了. 下 ...

  5. ThinkPHP3.1.3源码分析---php文件压缩zlib.output_compression 和 ob_gzhandler

    问题来源:\ThinkPHP3.1.3_full\ThinkPHP\Lib\Core\App.class.php 中 init()方法      if(C('OUTPUT_ENCODE')){     ...

  6. Office 2010 KMS激活原理和案例分享

    Office 2010 KMS激活原理和案例分享     为了减低部署盗版(可能包含恶意软件.病毒和其他安全风险)的可能性,Office 2010面向企业客户推出了新的批量激活方式:KMS和MAK.这 ...

  7. hdu-5493 Queue(二分+树状数组)

    题目链接: Queue Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  8. 异常总结<经典例题>

    public class Test1 { public static void main(String[] args) { try { add(1); System.out.println(" ...

  9. voxel 与 pixel

    中文名称:体素,即顾名思义是体积的像素.用来在三维空间中表示一个显示基本点的单位.类似于二维平面下的pixel(像素). voxel是三维空间中定义一个点的图象信息的单位.在平面中定义一个点要两个坐标 ...

  10. Unity3D粒子系统 合集

    http://www.cnblogs.com/qinyuanpei/p/3659513.htmlhttp://www.cnblogs.com/qinghuaideren/p/3597666.html