【转】C 编译器优化过程中的 Bug
C 编译器优化过程中的 Bug
一个朋友向我指出一个最近他们发现的 GCC 编译器优化过程(加上 -O3 选项)里的 bug,导致他们的产品出现非常诡异的行为。这使我想起以前见过的一个 GCC bug。当时很多人死活认为那种做法是正确的,跟他们说不清楚。简言之,这种有问题的优化,喜欢利用 C 语言的“未定义行为”(undefined behavior)进行推断,最后得到奇怪的结果。
这类优化过程的推理方式都很类似,他们使用一种看似严密而巧妙的推理,例如:“现在有一个整数 x,我们不知道它是多少。但 x 出现在一个条件语句里面,如果 x > 1,那么程序会进入未定义行为,所以我们可以断定 x 的值必然小于或者等于 1,所以现在我们利用 x ≤ 1 这个事实来对相关代码进行优化……”
看似合理,然而它却是不正确的,你能看出来这样的推理错在何处吗?我一时想不起来之前具体的例子了(如果你知道的话告诉我)。上网搜了一下相关话题,发现这篇 Chris Lattner (LLVM 和 Swift 语言 的设计者) 写于 2011 年的文章。文中指出,编译器利用 C 语言的“未定义行为”进行优化,是合理的,对于性能是很重要的,并且举出这样一个例子:
void contains_null_check(int *P) {
int dead = *P;
if (P == 0)
return;
*P = 4;
}
这例子跟我之前看到的 GCC bug 不大一样,但大致是类似的推理方式:这个函数依次经过这样两个优化步骤(RNCE 和 DCE),之后得出“等价”的代码:
void contains_null_check_after_RNCE(int *P) {
int dead = *P;
if (false) // P 在上一行被访问,所以这里 P 不可能是 null
return;
*P = 4;
}
void contains_null_check_after_RNCE_and_DCE(int *P) {
//int dead = *P; // 死代码消除
//if (false) // 死代码
// return; // 死代码
*P = 4;
}
他的推理方式是这样:
- 首先,因为在
int dead = *P里面,指针P的地址被访问,如果程序顺利通过了这一行而没有出现未定义行为(比如当掉),那么之后P就不可能是 null,所以我们可以把P == 0优化为false。 - 因为条件是
false,所以整个 if 语句都是死代码,被删掉。 dead变量赋值之后,没有被任何其它代码使用,所以对dead的赋值是死代码,可以消去。
最后函数就只剩下一行代码 *P = 4。然而经我分析,发现这个优化转换是根本错误的做法(unsound 的变换),而不只是像他说的“存在安全隐患”。现在我来考考你,你知道这为什么是错的吗?值得庆幸的是,现在如果你把这代码输入到 Clang,就算加上 -O3 选项,它也不会给你进行这个优化。这也许说明 Lattner 的这个想法后来已经被 LLVM 团队抛弃。
我写这篇文章的目的其实是想告诉你,不要盲目的相信编译器的作者们做出的变换都是正确的,无论它看起来多么的合理,只要打开优化之后你的程序出现奇葩的行为,你就不能排除编译器进行了错误优化的可能性。Lattner 指出这样的优化完全符合 C 语言的标准,这说明就算你符合国际标准,也有可能其实是错的。有时候,你是得相信自己的直觉……
【转】C 编译器优化过程中的 Bug的更多相关文章
- VS编译器优化诱发一个的Bug
VS编译器优化诱发一个的Bug Bug的背景 我正在把某个C++下的驱动程序移植到C下,前几天发生了一个比较诡异的问题. 驱动程序有一个bug,但是这个bug只能 Win32 Release 版本下的 ...
- SQL优化过程中常见Oracle HINT
在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...
- mysql优化过程中遇见的坑(mysql优化问题特别注意)
不要听信你看到的关于优化的“绝对真理”,包括本文所讨论的内容,而应该是在实际的业务场景下通过测试来验证你关于执行计划以及响应时间的假设. 单条查询最后添加 LIMIT 1,停止全表扫描. 对于char ...
- TensorRT优化过程中的dropout问题
使用tensorRT之前,你一定要注意你的网络结构是否能够得到trt的支持,无论是CNN还是RNN都会有trt的操作. 例如:tf.nn.dropout(features, keep_prob),tr ...
- 【填坑往事】Android手机锁屏人脸解锁优化过程实录
背景 写这篇文章,主要是为了以后面试方便.因为我简历上写了,上一份工作的最大亮点是将人脸解锁的速度由1200ms优化到了600ms,所以这些内容已经回答无数遍了.但每次总觉得回答的不完整,或者说总感觉 ...
- C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理
C#编译器优化那点事 使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的.优化代码 ...
- Bug,项目过程中的重要数据
作者|孙敏 为什么要做Bug分析? Bug是项目过程中的一个有价值的虫子,它不只是给开发的,而是开给整个项目组的. 通过Bug我们能获得什么? 积累测试方法,增强QA的测试能力,提升产品质量 发现项目 ...
- Coding过程中遇到的一些bug
1. 在使用layoutSubviews方法调整自定义view内部的子控件坐标时,最好不要使用子控件的centerX,centerY属性,否则会出现奇怪的bug. 如果一定要用,务必仔细检查,该子控件 ...
- Visual C++中的编译器优化
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:Visual C++中的编译器优化.
随机推荐
- android中RecyclerView控件的使用
1.RecyclerView控件不在标准的库里面,需要先引入,引入比较简单,点击控件右边的下载按钮即可 2.先添加一个新闻实体类,用来为新闻列表提供数据,news.java: package com. ...
- asp.net 定时执行任务代码 定时采集数据
using System; using System.Data; using System.Configuration; using System.Collections; using System. ...
- C#中使用多款LevelDB.Net封装测试性能
一.使用http://www.nuget.org/packages/LevelDB.NET 测试 1.新建项目,并Nuget引入库: 2.写代码 using LevelDB; using System ...
- angularjs图片上传和预览 base64
angularjs图片上传和预览 思路是从file中读取base64 Module.controller('controlName', ['$scope', '$http', function($sc ...
- Android 手把手带你玩转自己定义相机
本文已授权微信公众号<鸿洋>原创首发,转载请务必注明出处. 概述 相机差点儿是每一个APP都要用到的功能,万一老板让你定制相机方不方?反正我是有点方. 关于相机的两天奋斗总结免费送给你. ...
- python2x与3x下使用urlretrieve下载文件
1.python2x下urlretrieve方法: 直接将远程数据下载到本地. urllib.urlretrieve(url[, filename[, reporthook[, data]]]) 参数 ...
- Java多线程的悲观锁与乐观锁
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6561376.html 一:悲观锁 悲观锁,就是不管是否发生多线程冲突,只要存在这种可能,就每次访问都加锁,加 ...
- 〖Linux〗Kubuntu, the application 'Google Chrome' has requested to open the wallet 'kdewallet'解决方法
每次打开Google都提示: the application 'Google Chrome' has requested to open the wallet 'kdewallet'... 原来是Go ...
- jenkins相关默认路径
安装完成后,有如下相关目录:(1)/usr/lib/jenkins/:jenkins安装目录,WAR包会放在这里.( 2 ) /etc/sysconfig/jenkins:jenkins配置文件,“端 ...
- 了解 node.js
原文为: 我们为什么要使用NodeJS 写的好,就收藏于此,供学习之用. 科普文一则,说说我对NodeJS(一种服务端JavaScript实现)的一些认识,以及我为什么会向后端工程师推荐NodeJS. ...