日记239. STL 里面 coredump 了,如何定位?
作者:
| 更新日期:帮别人解决一个问题,分析过程分析一下。
本文首发于公众号:天空的代码世界,微信号:tiankonguse
一、问题背景
有天中午,团队里的核心主力 A 向我求助,说服务偶现 coredump,core 在 STL 里面,定位好几天了,怀疑 STL 有 BUG。
我说,一般情况下不要怀疑 STL 这种基础库,有问题一般都是我们自己代码的问题。
二、初步分析
一看 核心主力 A 屏幕上的 coredump 的堆栈,core 在 STL 的 map 里面了。
堆栈往上是 Github 上的开源库 antrl 的调用链,在使用 STL 的 map。
堆栈再继续往上是 业务代码,调用的开源库 antrl 。
开源库 antrl 是基于LL算法实现的语法解析器生成器,一般用于读取、处理、执行或翻译结构化文本或二进制文件。 程序语言编译器一般都会有这样一个语法解析模块,这个库也是做这个事情的。
看了一眼堆栈后,我说:既然 core 在 map 里了,肯定是并发操作 map 导致的。
怀疑 antrl 有并发问题或者业务并发调用了同一个 antrl。
核心主力 A 反馈自己读 antrl 代码了,antrl 好像没有并发问题。 而对于自己的业务代码,确认使用 antrl 都是局部变量。
我于是要到容器名,去看堆栈,要到代码,准备看下。
三、阅读源码
近两年,项目内的核心主力A 和核心主力B研究了这个库,并在自己的模块里使用了这个库。
他们对这个库算是相当熟悉了。 之前我一直想了解这个库,但又一直没找到机会,于是,我便想趁这个机会,来了解下这个库。
抱着了解这个库的心态来定位这个问题,打开堆栈后,我是从最外层一层层向里面看的。
这样的好处是可以快速了解到,这个服务是怎么使用这个库的,从而了解这个库的部分功能。
大概看了业务逻辑调用 antrl 的入口,发现一个很奇怪的方式,大家这种方式一般怎么写的呢?
看了业务的代码,发现确实都是局部变量,不同请求之间没有复用的资源。
然后一层层去看 antrl 的代码,结果看到 core 的那一行代码时,一眼就发现了问题。
如图,getPrecedenceStartState 函数读没有加锁,setPrecedenceStartState 函数写的时候加锁了。
看到这里,当然会猜测外面加的有锁。
但是不管外面有没有加锁,这里设计显然存在一致性问题:写在哪里加锁,读也应该在哪里加锁。
看外面的代码,发现读真的没有加锁。
那问题就确定了,读没加锁,写加锁,并发时就 coredump 了。
于是我给 核心主力 A 两个建议:要么设计保持一致,锁传进来。要么外面加锁。
四、最后
后来,我想起去 github antrl 看看官方的代码,发现最新的 master 也有这个问题。
当然,github antrl 现在已经修复这个BUG,所以我可以公开这个 BUG 以及经过了。
你使用过 antrl 或者 语法解析器生成器吗?
《完》
-EOF-
本文公众号:天空的代码世界
个人微信号:tiankonguse
本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。