给yaf项目贡献了一次bugfix

因为公司需要,这几天在搞yaf框架,遇到了有意思的事情,特别值得记录下来。

学习yaf

用yaf有2个原因:

  • 性能高:C扩展实现的mvc框架。
  • 简单:yaf只提供最小化的mvc框架功能,容易掌握,方便扩展。

yaf并不难学,大家可以看这个教程搞定:系统学Yaf框架,鸟哥自己写的教程也要读一下:Yaf教程

在实际编码过程中,大家可以参考这些文档来快速的查找类定义,历史bug列表,以及建议用法:

看完理论,实践基本不会遇到什么问题,至少我是这样的。

注意事项

鸟哥在yaf github里提供了项目模板的生成工具,大家一定要使用。

另外,鸟哥提供了框架类(C实现的)对应的PHP定义文件,你可以引入到项目里,这样IDE就可以自动提示和跳转到Yaf的类定义了。

遇到的坑

其实整个二次开发yaf框架的过程中没有遇到使用上的问题,但是有一个必须说一下:yaf的类自动加载是将类名中的_替换成目录分隔符/,并直接去磁盘上查找的,也就是说文件路径是大小写敏感的。

我一开始在mac上开发yaf,发现即便类名和文件名的大小写不对应,也可以成功加载到类,看yaf的c源码发现并没有对应的大小写统一逻辑。最终,我获知mac操作系统的文件系统默认不区分文件路径的大小写,简直想杀人!

公司内分享用的PPT

给公司内做了一个PPT分享yaf框架,大家可以简单参考,但是改造后框架源码就不方便上传了,一方面是公司限制,一方面框架是针对公司之前框架的开发习惯进行订制的,不一定适合大家。

yaf_share

我给yaf贡献bugfix

在压测yaf过程中,发现php7+opcache环境下随机抛出异常,意思就是:类找不到。

发现问题后,我先自己分析了yaf_loader.c代码,基本上理清了整个文件的核心逻辑(PS:我不懂php扩展开发,但是我会C语言),但没有什么好的办法找到bug点。

然后我就去github上提交了一个issue,偶然发现issue列表中已经有其他朋友提交过几个类似的issue。

其中,比较重要的线索就是这个问题与opcache有关,关闭opcache就没有问题。还有一个线索是说yaf-3.0.3没有问题,yaf-3.0.4有问题。

因此,我首先关闭opcache确认了这个线索是可靠的,然后我通过git diff yaf-3.0.3:yaf_loader.c yaf-3.0.4:yaf_loader.c,着手分析这2个release之间的差异代码。

但仍旧没有发现bug点,因此在这个issue里https://github.com/laruence/yaf/pull/360,我将自己的猜测留言给了鸟哥,并与鸟哥进行一系列的对话。

最终在鸟哥的指导下,开启了opcache的memory protection,再次请求接口成功出core。

通过gdb php-fpm coredump文件,成功看了堆栈,之所以产生coredump是因为yaf_loader.c里某个逻辑,会直接修改取自zend的内存,因为开启了opcache的memory protection,因此100%会出core。

有了coredump,思路异常的清晰,因为之前排查过程中我已经对yaf_loader.c的代码非常熟悉,因此我很快找到了一个代码分支是会直接修改zend内存,而不是副本。

修改了对应的实现后重新编译yaf.so,果然没有问题了!

按照github的开源项目工作流程,我fork了yaf项目,并在自己的分支下提交了我的patch,向鸟哥发起了pull request。

鸟哥原先的代码并没有改变zend内存的内容,只是临时改变了里面的1个字符,之后立即复原了,不应该对zend和opcache造成什么影响,所以我在pull request里与鸟哥又进行了一些交流:https://github.com/laruence/yaf/pull/360

最终,鸟哥给的结论是:opcache在共享内存里保存了字符串,多个php-fpm进程可能共同访问,因为bug的原因会导致其他进程访问到脏数据。

鸟哥并没有直接采纳我的commit,因为我的修复代码会导致下面的一个if代码没必要再执行,鸟哥对其做了二次修改,删减了无用的代码,patch如下:

第一个箭头是bug点,鸟哥看了patch后发现file_name总是副本,所以删掉了下面的if,总是free掉这块内存。

幸运!

这个bug严重性很高,最新的yaf relase 3.0.4在php7+opcache下基本是不可用,因此鸟哥在merge后立即发布了新的release 3.0.5,哈哈!

这次经历给我的感受就是:鸟哥把yaf当自己的孩子,响应真的是太及时了。

 

 

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~