Press "Enter" to skip to content

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

本来是发在长微博的, 不过, 鉴于, 好久没更新博客了...... 就转过来, 凑个数吧, 大家凑合着看 🙂
白忙活了近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读取了0x10(%rdx)位置上的一个word大小的数据, %rdx此时是zend_string op的指针, 而0x10偏移是str->len. 原来是因为GCC优化很聪明的把

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

优化成了和一个数据0x3000000001比较的一条指令....
于是, 如上面所说, 因为这个str只有22个bytes, 当尝试从16偏移处尝试读取8个字节的时候, 我们其实多读了str结构体外面的3个字节...... 于是就invalid read了
问题清楚了, GCC聪明的优化, 引起的一个无害的报告(and 0xffffffffff)............ 于是, 白忙活了.... (当然, 最好还是修复掉, 我现在打算的修复就是, 最小也要分配一个24bytes).

27 Comments

  1. bahisnow
    bahisnow October 22, 2020

    adam adamı yer bende seni admin

  2. y8
    y8 May 1, 2020

    very nice article, thanks for sharing.

  3. Harry Hill
    Harry Hill March 27, 2020

    I really enjoy typing fast and listening to the music at the same time, I kind of feel motivated.

  4. Elexbet
    Elexbet December 1, 2019

    Elexbet giriş adresi için sitemize bakabilir ve yeni giriş adresiyle üyelik alabilirsiniz! %100 üyelik casino bonusunu kaçırmayın!

  5. xayah
    xayah October 8, 2019

    春節過後,我忘了更新博客。

  6. cristiano
    cristiano October 8, 2019

    春節過後,我更新了博客。

  7. happy wheels
    happy wheels May 24, 2019

    Your article is very useful, the content is great, I have read a lot of articles, but for your article, it left me a deep impression, thank you for sharing.

  8. candy crush soda
    candy crush soda May 23, 2019

    Love it, it’s definitely important to know how to do this properly and efficiently, clients LOVE these.

  9. megadede
    megadede May 17, 2019

    Despite the fact that this type of payment structure can get fairly expensive.

  10. happywheels24.com
    happywheels24.com December 21, 2018

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

  11. alvin
    alvin August 31, 2017

    鸟哥,学了几年的PHP,感觉没有质的提升,能请教下吗?

  12. f10messi
    f10messi March 3, 2015

    过年回来没有更新blog,待新作

  13. cping12345
    cping12345 February 25, 2015

    众所周知,PHP就是最好的语言。偶然经过贵站,盼望回访,xrpmoon

  14. tunpishuang
    tunpishuang January 14, 2015

    内存对齐的问题确实很容易忽视。学习了。。。。

  15. 聚能量
    聚能量 November 28, 2014

    好博客,内容正是我需要的。

  16. ccg
    ccg September 5, 2014

    _zend_string结构体指定字节对齐为1
    #pragma pack(1)
    是否可以解决问题

  17. 23213213
    23213213 August 23, 2014

    34324324

  18. t.k.
    t.k. August 12, 2014

    看来问题的关键还是gcc认为有padding,但是这段代码的申请方式不是用普通sizeof。我想如果修改gcc的padding参数或许能在使用现有代码的基础上避免此问题。

  19. kalcaddle
    kalcaddle July 19, 2014

    推荐一个php版的开源web文件管理软件KodExplorer,
    可以取代ftp,方便对网站进行备份、解压缩,文件夹拖拽上传;
    在线编辑器 webIDE(60多种代码高亮,自动补全)
    可以体验下:http://www.kalcaddle.com/download.html
    支持开源!

  20. goghcrow
    goghcrow June 28, 2014

    高大尚

Leave a Reply

Your email address will not be published. Required fields are marked *