VS编译器优化诱发一个的Bug
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的更多相关文章
- 【转】C 编译器优化过程中的 Bug
C 编译器优化过程中的 Bug 一个朋友向我指出一个最近他们发现的 GCC 编译器优化过程(加上 -O3 选项)里的 bug,导致他们的产品出现非常诡异的行为.这使我想起以前见过的一个 GCC bug ...
- 探索c#之尾递归编译器优化
阅读目录: 递归运用 尾递归优化 编译器优化 递归运用 一个函数直接或间接的调用自身,这个函数即可叫做递归函数. 递归主要功能是把问题转换成较小规模的子问题,以子问题的解去逐渐逼近最终结果. 递归最重 ...
- 翻译「C++ Rvalue References Explained」C++右值引用详解 Part6:Move语义和编译器优化
本文为第六部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...
- gcc编译器优化给我们带来的麻烦???
gcc编译器优化给我们带来的麻烦??? 今天看到一个很有趣的程序,如下: ? 1 2 3 4 5 6 7 8 9 int main() { const int a = 1; int * ...
- C#编译器优化那点事
使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的. 优化代码开关即optimize开 ...
- C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理
C#编译器优化那点事 使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的.优化代码 ...
- C#编译器优化
C#编译器优化 https://www.cnblogs.com/podolski/p/8987595.html 使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置 ...
- js动画--一个小bug处理下
对于上面的课程我们很好的处理了一个小bug,那么我们现在讲程序进行优化一下,前一节的程序中,我们处理处理的属性都是写死了的.为了我们能够很好的对某个属性进行操作的话.我们这样来设置. js文件 win ...
- 2018-8-10-win10-uwp-禁止编译器优化代码
title author date CreateTime categories win10 uwp 禁止编译器优化代码 lindexi 2018-08-10 19:16:50 +0800 2018-2 ...
随机推荐
- WPF学习之路(四)路由
路由事件概述 功能定义:路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件. 实现定义:路由事件是一个 CLR 事件,可以由RouteEvent 类的实例提供 ...
- jsp学习笔记一
page属性 定义JSP文件中的全局属性. 实例: <%@ page language="java" contentType="text/html; charset ...
- Sql Server之旅——第三站 解惑那些背了多年聚集索引的人
说到聚集索引,我想每个码农都明白,但是也有很多像我这样的猥程序员,只能用死记硬背来解决这个问题,什么表中只能建一个聚集索引, 然后又扯到了目录查找来帮助读者记忆....问题就在这里,我们不是学文科,, ...
- js实现页面跳转的几种方式
第一种: <script language="javascript" type="text/javascript"> wi ...
- 今天说一下DML触发器的顺序
因为05之后的版本允许了一个对象有多个after触发器,所以呢~顺序方面还是要留意一下下的.比如我现在要往一个测试表里面添加多个触发器. USE Test GO ,),Name )) GO CREAT ...
- CentOS 7最小化安装后找不到‘ifconfig’命令——修复小提示
如果你不知道在哪里可以找到ifconfig命令,请按照以下简单的步骤来找到它.首先,让我们找出哪个包提供了ifconfig命令.要完成这项任务,输入以下命令: [root@jrserver app_f ...
- 初识Hadoop入门介绍
初识hadoop入门介绍 Hadoop一直是我想学习的技术,正巧最近项目组要做电子商城,我就开始研究Hadoop,虽然最后鉴定Hadoop不适用我们的项目,但是我会继续研究下去,技多不压身. < ...
- linux enc28j60网卡驱动移植(硬件spi和模拟spi)
本来想移植DM9000网卡的驱动,无奈硬件出了点问题,通过杜邦线链接开发板和DM9000网卡模块,系统上电,还没加载网卡驱动就直接崩溃了,找不到原因...刚好手上有一个enc28j60的网卡模块,于是 ...
- android 设置布局为无标题样式
<!-- Application theme. --> <style name="AppTheme" parent="android:Theme.Lig ...
- nodejs模块——http模块
http模块主要用于创建http server服务. 本文还用到url模块和path模块,还有fs模块.url模块用于解析url,path模块用于处理和转换文件路径. 一.简单应用 代码如下: // ...