GCC优化引起的一个”问题”

作者: Laruence( ) 本文地址: http://www.laruence.com/2014/06/26/2955.html 转载请注明出处

本来是发在长微博的, 不过, 鉴于, 好久没更新博客了…… 就转过来, 凑个数吧, 大家凑合着看 :)

白忙活了近2个小时,不吐不快:

一切要从今天下午5点左右说起, 调试一个扩展, 用valgrind(valgrind-3.8.1)做例行检查, 很不幸的valgrind报告invalid read:

db attach上去以后, 发现报告错误的地方是:

因为在PHP NG(PHP New Generation)中, 使用了新的字符串结构来保存字符串, 也就是zend_string:

而排查了半天, 我确认这个op是经过正常初始化的, 那问题出在哪里呢?

突然看到op是一个长度为1的字符串”0″, 就突然想起来, 之前我们做了个很”精细”的优化, 因为对于上面的结构体, 在64位的系统上, sizeof它, 由于padding, 实际上会得到大于8 + 8 + 4 + 1(21) 的大小(8 + 8 + 8 = 24).

所以我们不会使用一般来说的做法:

str = malloc(sizeof(str) + len + 1)

来为一个长度为len的字符串申请内存. 而是会使用类似:

str = malloc ((int)((str*)0)->val) + len + 1)

的方式来为一个字符串申请内存, 所以对于”0″, 我们实际上申请分配的内存是22bytes.

但, 又会有什么问题呢? 于是让我们再次db attach上去, disassmble下看看具体是什么原因:

恩, 问题就出在f3b5这行, GCC读取了0×10(%rdx)位置上的一个word大小的数据, %rdx此时是zend_string op的指针, 而0×10偏移是str->len. 原来是因为GCC优化很聪明的把

if (str->len == 1 && str->val[0] == '0')

优化成了和一个数据0×3000000001比较的一条指令….

于是, 如上面所说, 因为这个str只有22个bytes, 当尝试从16偏移处尝试读取8个字节的时候, 我们其实多读了str结构体外面的3个字节…… 于是就invalid read了

问题清楚了, GCC聪明的优化, 引起的一个无害的报告(and 0xffffffffff)………… 于是, 白忙活了…. (当然, 最好还是修复掉, 我现在打算的修复就是, 最小也要分配一个24bytes).

Comments

2014/06/28, goghcrow writes: 高大尚2014/07/19, kalcaddle writes: 推荐一个php版的开源web文件管理软件KodExplorer, 可以取代ftp,方便对网站进行备份、解压缩,文件夹拖拽上传; 在线编辑器 webIDE(60多种代码高亮,自动补全) 可以体验下:http://www.kalcaddle.com/download.html 支持开源!2014/08/12, t.k. writes: 看来问题的关键还是gcc认为有padding,但是这段代码的申请方式不是用普通sizeof。我想如果修改gcc的padding参数或许能在使用现有代码的基础上避免此问题。2014/08/23, 23213213 writes: 343243242014/09/05, ccg writes: _zend_string结构体指定字节对齐为1 #pragma pack(1) 是否可以解决问题2014/11/28, 聚能量 writes: 好博客,内容正是我需要的。2015/01/14, tunpishuang writes: 内存对齐的问题确实很容易忽视。学习了。。。。2015/02/25, cping12345 writes: 众所周知,PHP就是最好的语言。偶然经过贵站,盼望回访,xrpmoon2015/03/03, f10messi writes: 过年回来没有更新blog,待新作2016/06/23, Juca Curso Recepcionista hotel writes: 我仍然在学习如何乱用PHP,但我喜欢学习多一点。2017/08/31, alvin writes: 鸟哥,学了几年的PHP,感觉没有质的提升,能请教下吗?2017/12/07, 鳄鱼皮钱包 writes: 学习了,经常看还是能看的懂一点Copyright © 2010 风雪之隅 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)

Related Posts:

一个小玩意PHP-Valgrind的介绍HTTPOXY漏洞说明让你的PHP7更快(GCC PGO)在PHP中使用协程实现多任务调度记录一场没有胜利的局部战斗Curl的毫秒超时的一个”Bug”Weibo LAMP演变 – 6月在上海分享的PPTPHP浮点数的一个常见问题的解答Yaf and Phalcon, which is faster?Yar – 并行的RPC框架(Concurrent RPC framework)

文章来源:

Author:Laruence
link:http://www.laruence.com/2014/06/26/2955.html