问题描述:

修改跟踪程序(Trace)支持IPV6时,发现程序启动后正常,但是客户端一旦下发查询条件进行跟踪,Trace程序就直接coredump!

 (gdb) bt
# 0x00007f7dab9e5adb in ComponentImpl::AddProperty(Property*) ()
from libbuilder.so
# 0x00007f7daa5a8964 in TimerLogic::InitDeclaration() () from libplat.so
# 0x00007f7dabfab93c in Thread::startThread(void*) () from libbase.so
# 0x00007f7dac42f7b6 in start_thread () from /lib64/libpthread.so.
# 0x00007f7daad8dd6d in clone () from /lib64/libc.so.
# 0x0000000000000000 in ?? ()
(gdb)

简单的描述下程序功能:

Trace接收后端送入的数据,同时接收前端送入的查询条件,若数据匹配查询条件,返回该数据!

coredump相关信息:

Trace有一个Timer类(通过启动一个单独线程执行定时任务检测和唤醒计划任务),该类继承自平台Thread类(Thread设置线程亲和性,通过startThread启动一个线程,最后调用子类的main方法),从代码角度看,两个类都没有引用TimerLogic。

调试Trace程序时候,发现Timer类启动线程后,线程还没有运行到Timer::main函数就core了。继续调试,还是没有什么进展,不能确定错误地方!决定先通过回退版本来验证是哪一处修改导致的问题,找到修改点后再进行排查!

由于在之前平台除了开源治理和kw治理外,有过两次较大的更新:

a) 用jemalloc替换了tcmalloc

b) 为了上层应用能适配现网大流量数据处理,平台进行了大幅优化!

不怀疑jemalloc库替换会导致core问题,主要还是怀疑平台优化这些代码!从git仓库checkout了这几次提交对应的版本测试,发现在平台优化代码的前一个版本Trace程序运行正常,而提交了优化代码的版本确实导致了Trace程序core!

平台代码优化没有更新过core报错的这一块代码,为了验证Thread类,先屏蔽了业务Timer类启动功能,直接在业务程序里新增了一个Test类继承自Thread,只在线程中打印一个自增变量,以此来判断程序会不会core,结果发现程序运行正常!

这时再屏蔽业务Timer类所有的功能代码,也仅仅在线程中循环打印一个自增变量,发现几乎和Test类相同的代码依然core!

这时想到平台也有一个Timer类(该类继承自TimerLogic),平台和业务Timer类的文件名两者也相同,暗想会不会是这个原因导致运行时重定位错误,从而导致程序运行core!直接重命名业务程序Trace的Timer类为SSTimer,修改所有调用代码后,运行正常!

------------------------------------------------------------------------------------------------------------------------------

Trace程序启动时会通过命令行先加载libplat.so, 然后加载libTrace.so(启动命令:Trace libplat.so libTrace.so),  从下面的修改前和修改后符号信息推测, core的版本启动后relocation根据加载的符号优先级(顺序),会优先把libplat.so里面的Timer::main函数加载到全局符号表(Global Symbol Table),最终导致客户端下发查询条件时业务Trace程序启动自身Timer::main时crash。尝试把启动命令后so顺序轮换下,由于底层启动时会用到平台Timer,预测Trace程序启动就会crash,测试结果验证了这一点。

# 修改Trace类Timer名称前
Trace # objdump -t libTrace.so | grep Timer | grep main
0000000000083a20 g F .text 0000000000000058 _ZN5Timer4mainEv
Trace # objdump -t libplat.so | grep Timer | grep main
00000000000581e0 g F .text 0000000000000087 _ZN5Timer4mainEv
00000000000581d0 g F .text 0000000000000006 _ZThn112_N5Timer4mainEv
Trace # nm libTrace.so | grep Timer | grep main
0000000000083a20 T _ZN5Timer4mainEv
Trace # c++filt _ZN5Timer4mainEv
Timer::main()
Trace # nm libplat.so | grep Timer | grep main
00000000000581e0 T _ZN5Timer4mainEv
00000000000581d0 T _ZThn112_N5Timer4mainEv
Trace # c++filt _ZN5Timer4mainEv
Timer::main()
Trace #

  

# 修改Trace类Timer名称为SSTimer后
Trace # objdump -t libTrace.so | grep Timer | grep main
0000000000084420 g F .text 00000000000003bd _ZN7SSTimer4mainEv
Trace # objdump -t libplat.so | grep Timer | grep main
0000000000064160 g F .text 0000000000000059 _ZN5Timer4mainEv
0000000000064150 g F .text 0000000000000006 _ZThn112_N5Timer4mainEv
Trace # nm libTrace.so | grep Timer | grep main
0000000000084420 T _ZN7SSTimer4mainEv
Trace # c++filt _ZN7SSTimer4mainEv
SSTimer::main()
Trace # nm libplat.so | grep Timer | grep main
0000000000064160 T _ZN5Timer4mainEv
0000000000064150 T _ZThn112_N5Timer4mainEv
Trace # c++filt _ZN5Timer4mainEv
Timer::main()
Trace #

由于修改前Trace程序运行正常,直接查看平台dll加载代码,发现确实是更新了此处代码引入的问题:

RTLD_GLOBAL : 动态库中定义的符号可被其后打开的其他库解析。
RTLD_LOCAL    : 动态库中定义的符号不能被其后打开的其他库重定位, 与RTLD_GLOBAL作用相反。

dlopen如果没有明确指定选项是RTLD_GLOBAL还是RTLD_LOCAL,默认使用RTLD_LOCAL。删除代码里新增的RTLD_GLOBAL测试,此时Trace程序正常运行!

# 删除dlopen加载参数RTLD_GLOBAL符合信息,看起来和不删没有不同
Trace # objdump -t libplat.so | grep Timer | grep main
0000000000057f90 g F .text 0000000000000059 _ZN5Timer4mainEv
0000000000057f80 g F .text 0000000000000006 _ZThn112_N5Timer4mainEv
Trace # objdump -t libTrace.so | grep Timer | grep main
0000000000084000 g F .text 00000000000003bd _ZN5Timer4mainEv
Trace # nm -A libplat.so libTrace.so | grep Timer | grep main
libplat.so:0000000000057f90 T _ZN5Timer4mainEv
libplat.so:0000000000057f80 T _ZThn112_N5Timer4mainEv
libTrace.so:0000000000084000 T _ZN5Timer4mainEv
Trace # c++filt _ZN5Timer4mainEv
Timer::main()
Trace #

  

------------------------------------------------------------------------------------------------------------------------------

一些待改进的地方:

1. 合入优化代码的时候分为了多个commit(编译错误解决,导致其它业务运行时报错等问题的解决),导致其它一些提交夹杂期间(像jemalloc替换,kw修改等),导致取版本测试花费了较多时间(运行时报错以为发现一个问题,后发现是在后续提交修复了的代码),为了彻底排除是jemalloc等代码造成的问题,最后是在优化代码的第一个提交上手动合入了后续的错误修正代码进行测试!

这说明组内代码提交前还是应该要先进行充分的测试,特别是涉及到平台组件更新,更应该慎重!不能把版本库和genkins/自动化当成代码验证的环境,同时最好能一次就提交完成,这对于gerrit代码走查和checkout也有帮助!

2. 平台代码支持了命名空间,但现在没有启用!后续所有模块都应该考虑启用命名空间!

一个符号冲突导致的core分析的更多相关文章

  1. CPU指令集不同导致的core分析

    最近程序需要支持CGSL系统运行,测试中发现相同操作系统的两台机器,编译机运行正常,测试机coredump.core信息汇总如下,可以看出是由于测试机不支持编译后的指令导致的问题: Program t ...

  2. linux 动态库的符号冲突问题

    最近,给同事定位了一个符号表的冲突问题,简单记录一下. A代码作为静态链接库,被包含进了B代码,然后编译成了动态链接库,B.so A代码同时作为静态链接库,被编译进入了main的主代码. main函数 ...

  3. C++写一个简单的解析器(分析C语言)

    该方案实现了一个分析C语言的词法分析+解析. 注意: 1.简单语法,部分秕.它可以在本文法的基础上进行扩展,此过程使用自上而下LL(1)语法. 2.自己主动能达到求First 集和 Follow 集. ...

  4. docker - 由于docker swarm子网与host机器网络冲突导致的container通信问题的解决方案

    背景 近期,公司网络要迁移到新的网段,所以原来在服务器上面搭建的docker swarm需要重新构建... 拿到新的服务器地址看了一下,“10.xxx.xxx.xxx" ... 纳尼,这IP ...

  5. centos7安装Python3的过程中会和Python2.7版本冲突导致yum版本比对应,致使yum不能使用的问题。

    centos7安装Python3的过程中会和Python2.7版本冲突导致yum版本比对应,致使yum不能使用的问题. 原因:yum调用Python,启动程/usr/bin/yum就是一个python ...

  6. 关于VirtualBox与锐捷冲突导致锐捷不断掉线的问题的解决办法

    和VM一样,virtualBox也是和锐捷冲突,网上有一些方法是禁用虚拟网卡,但是还是会导致锐捷客户端掉线,除非使用wifi 第一个解决办法: 偶然看到一个解决办法是,在锐捷客户端登陆之后,打开任务管 ...

  7. art-template与swiper发生冲突导致swiper的一些样式不起作用

    我们在实际中的前后端分离开发中,在进行渲染后端返回来的数据时我们有时会用到模板来进行渲染数据,而在渲染数据中我们可能用到一些组件来进行一些样式显示.而在页面中数据显示了导致组件的一些样式没有显示,一些 ...

  8. 从一个弱引用导致的奔溃 谈 weak assign strong的应用场景【iOS开发教程】

    从一个弱引用导致的奔溃 谈 weak assign strong的应用场景 .h中的定义方法一: @property (nonatomic, assign) NSArray *dataSource; ...

  9. 解决genemotion模拟器冲突导致的Android Studio无法启动ADB的问题

    首先命令行下运行 adb nodaemon server ./adb nodaemon server (Mac OSX) 如果出现错误: error: could not install *smart ...

随机推荐

  1. 机器学习实战之Logistic回归

    Logistic回归一.概述 1. Logistic Regression 1.1 线性回归 1.2 Sigmoid函数 1.3 逻辑回归 1.4 LR 与线性回归的区别 2. LR的损失函数 3. ...

  2. CNN中卷积的意义

    在传统的神经网络中,比如多层感知机(MLP),其输入通常是一个特征向量.需要人工设计特征,然后将用这些特征计算的值组成特征向量.在过去几十年的经验来看,人工找的特征并不总是好用.有时多了,有时少了,有 ...

  3. Githug攻略

    ruby运行环境安装 githug 是一个 ruby 程序,运行的 githug 需要 ruby 运行环境.下面部分的主要内容是如何在不同平台上安装好 ruby 环境. MacOSX MacOSX 里 ...

  4. pdo->prepare 返回false的问题总结

    报错信息: Fatal error: Call to a member function execute() on a non-object 一般是pdo->prepare 返回了false导致 ...

  5. Qt.5.9.6移植

    工具及软件包 交叉编译工具链 arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2 软件包 dbus-1.10.0.tar.g ...

  6. BZOJ4128: Matrix(BSGS 矩阵乘法)

    Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 813  Solved: 442[Submit][Status][Discuss] Descriptio ...

  7. 微信 php 获取token 第二次失败解决办法

    第一次成功了,第二次总是失败,很简单,session问题 clearstatcache(); $_SESSION = ''; $_COOKIE = ''; //获得参数 signature nonce ...

  8. 在github上查找star最多的项目

    如何在github上查找star最多的项目 在search中输入stars:>1 就可以查找所有有star的项目,然后右上角根据自己的需要筛选 当我输入stars:>10000的时候,就会 ...

  9. Eclipse搭建SpringBoot

    第一种方法(不建议) 首先新建Maven工程 勾选第一个按钮,第三个是选择working set ,你可以不选 下一步,配置工程信息,注意打包为jar 打开pom.xml文件,添加spring-boo ...

  10. MySQL安装在Linux

    利用Alt+p工具将下载好的Linux版本的mysql软件加载到根目录. 1. 将下载好的MySQL文件MySQL-5.6.41-1.el6.i686.rpm-bundle.tar放到 根目录下的mk ...