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. OEM代工厂产品经理个人经历谈

    创业不是一件随随便便的事情! 到2007年时,我已经在上海.广州.东莞三地的工厂打工有十来年了.正是这个时间结点,我也即将做父亲了.打了很久的工后,就开始感到疲倦,做来做去,都是给老板做,也就在这时开 ...

  2. Web Service 的工作原理

    Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的 ...

  3. Java对象的序列化

    1.概念 序列化:把Java对象转换为字节序列的过程. 反序列化:把字节序列恢复为Java对象的过程. 2.用途 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个 ...

  4. DGbroker三种保护模式的切换

    1.三种保护模式 – Maximum protection 在Maximum protection下, 可以保证从库和主库数据完全一样,做到zero data loss.事务同时在主从两边提交完成,才 ...

  5. c# ref 的作用

    Usage of ref keyword in C#  When we pass a value type variable as a parameter, then it passes its va ...

  6. Java设计模式 - 代理模式

    1.什么是代理模式: 为另一个对象提供一个替身或占位符以访问这个对象. 2.代理模式有什么好处: (1)延迟加载 当你需要从网络上面查看一张很大的图片时,你可以使用代理模式先查看它的缩略图看是否是自己 ...

  7. 深度学习笔记------windows系统下进行Linux-Ubuntu14.04双系统安装笔记(二)

    在上一篇文章中介绍了新手如何安装Ubuntu14.04的双系统,本文会说明Ubuntu系统下搜狗输入法的安装,并就我遇见的一些bug给出最简单的解决办法. 第一部分.搜狗输入法的安装 本身搜狗输入法的 ...

  8. 2. Docker - 安装

    一.Docker介绍 1. Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上, 也可以实现虚拟化. 容器时完全使用沙 ...

  9. centos yum源配置

    5步搞定yum源配置 作者小波/QQ463431476欢迎转载! 第一步: 卸载原来的yum [root@localhost home]#rpm -qa|grep yum|xargs rpm -e - ...

  10. C# 为私有方法添加单元测试(反射)

    1: using System; 2: using System.Collections.Generic; 3: using System.Linq; 4: using System.Text; 5: ...