qsort多线程下core dump分析

来源:互联网 发布:淘宝分期买手机靠谱吗 编辑:程序博客网 时间:2024/06/06 03:48
Glibc 2.9.93 qsort多线程下core dump分析

本文转自:http://www.youalab.com/?p=72

Posted on2010/09/19byyouaadmin
1 问题:

一个C实现的32位多线程服务在启动时core dump. 该服务运行了一年多,而此问题仅出现了一次,是一个比较难复现的问题。 出core的位置

在C库的qsort函数,信号是signal 8(算术错).
2 定位:

core的栈的结构如下:
#0 0x4202a801 in qsort () from /lib/i686/libc.so.6
#1 0x0804e74e in getFRes (databuf=0x406697fc) at fs.cpp:128
#2 0x0804ea74 in adjustOrder (databuf=0x406697fc) at fs.cpp:233
#3 0x0804e553 in Search (databuf=0x406697fc) at fs.cpp:66
#4 0x0804e4b8 in getBResponse (databuf=0x406697fc) at fs.cpp:29
#5 0x0804c559 in getResponse (databuf=0x406697fc) at fs.cpp:283
#6 0x0804c292 in thread_main (arg=0x1) at fs.cpp:222
#7 0x40020941 in pthread_start_thread () from /lib/i686/libpthread.so.0

可以先通过GDB的命令查看出core的汇编指令。当程序core时,$eip保存了当时程序运行指令地址。通过x /i 命令可以将内存以汇编指令的

方式查看。 这样就可以得到core dump时运行的汇编指令。如下:
(gdb) x /i $eip

0x4202a801 <qsort+65>: divl 0x724(%ebx)

按汇编看,应该是除法指令出问题,一般觉得会是除数为0之类的错误 由于glibc是开源的,可以查看一下qsort原代码,此处要注意版本问

题,要下相同的版本才能方便问题定位。不同linux发行版带的glibc的版本可能是不同的,而且系统维护人员也可能升级过相关的库。 通过以

下几个命令可以查看系统的glibc版本。
$ ldd ./bin/fras libpthread.so.0 =>/lib/i686/libpthread.so.0 (0x4001a000)

libcrypto.so.2 =>/lib/libcrypto.so.2 (0x4004b000) libc.so.6 =>/lib/i686/libc.so.6 (0x42000000)

libdl.so.2 =>/lib/libdl.so.2 (0x4011f000)/lib/ld-linux.so.2 =>/lib/ld-linux.so.2 (0x40000000)
/lib/i686/libc.so.6 (0x42000000) libdl.so.2 =>/lib/libdl.so.2 (0x4011f000) /lib/ld-linux.so.2 =>/lib/ld-linux.so.2 (0x40000000)

$ /lib/i686/libc.so.6 -v GNU C Library development release version 2.2.93 , by Roland McGrath et al. Copyright (C)1992-2001, 2002

Free Software Foundation, Inc. This is free software; see the sourcefor copying conditions. There is NO warranty; not even for

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 3.2 20020903(Red Hat Linux 8.03.2-7)

. Compiled on a Linux 2.4.9-9 system on 2002-09-05. Available extensions:

下载glibc 2.2.93版本,查看其qsort实现,以下为简化版的原代码
void qsort (void*b, size_t n, size_t s, __compar_fn_t cmp)
{

const size_t size = n * s;

if(size < 1024)

{

void*buf = __alloca (size);

/* The temporary array is small, so put it on the stack. */

msort_with_tmp (b, n, s, cmp, buf);

}

else

{

staticlong int phys_pages;

static int pagesize;

if(phys_pages ==0)

{

phys_pages = __sysconf (_SC_PHYS_PAGES);

if(phys_pages ==-1)

phys_pages = (longint)(~0ul >>1);

phys_pages /=4;

pagesize = __sysconf (_SC_PAGESIZE);

}

if(size / pagesize > phys_pages)

_quicksort (b, n, s, cmp);

......

}
}

根据错误类型(除法错),可以看到出问题的指令刚好对应代码中黑体部分(size / pagesize > phys_pages); 接下来的问题就相对简单了,程

序中有两个static变量如下
staticlongint phys_pages;
static int pagesize;

在多线程情况下,线程A先运行到第一处黑体代码,静态变量 phys_pages 的值将被修改,即不为0,而pagesize未被赋值. 若此时发生线程

切换,线程B开始运行,到分支判断处phys_pages已不为0,所以else条件将被执行,而此时由于pagesize变量尚未被赋 值,结果 (size /

pagesize)这一步就发生除0错误了。所以,core dump时的表现就是signal 8即算术错。

3 解决: 可见,该glibc版本的qsort函数不是多线程安全的。 在不修改glibc的基础上,可以考虑绕过此问题的办法:
在主程序(线程未启动时)中先调用qsort一次,为static变量赋上值。
需要注意的:初始化时,n*s必须大于1024,否则pagesize没进行初始化。

–EnD–
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 qq糖粘在喉咙气管里怎么办 穿上旗袍后感觉后腰处不平整怎么办 机打票给客人给错联怎么办?急 ps修证件照感觉不太立体怎么办 手机百度上下载的文档打不开怎么办 5岁宝宝乘飞机没带证件怎么办 网上订飞机票忘记订儿童票了怎么办 两岁宝宝对牛奶鸡蛋过敏了怎么办 两岁宝宝坐不住好跑怎么办 宝宝两岁多了不愿意坐小马桶怎么办 坐火车小孩拉屎在被子上怎么办 川航飞机票名字错了一个字怎么办 胜战本领怎么看走向战场怎么办 数数字油画你的颜料干了怎么办? 数字油画涂颜料涂错了怎么办 绝地求生模拟器注册已达上限怎么办 孕妇把番茄和虾一起吃了怎么办 4岁宝贝吃了玩具小电池怎么办 微信使用零钱需完善实名信息怎么办 两岁宝宝刷牙不会吐水怎么办 孩子牙龈上长了小牙怎么办 供暖公司未供暖却收取供暖费怎么办 两岁宝宝认知和语言能力低怎么办 蜡笔同步被对方发现删掉的怎么办 微信时间和手机时间不同步怎么办 孩子们家乡爱画美丽的也自己怎么办 娃把豆豆弄进鼻孔了怎么办 20岁了不知道自己该干什么怎么办 遇到一个新手买家恶意拍下怎么办 淘宝卖螃蟹有什么要求美工怎么办 淘宝衣服吊牌剪了想退货怎么办修 用图片在淘宝搜衣服搜不到怎么办 汽车黑塑料水砂纸磨的不平怎么办 sat报名要你填10位电话怎么办 手绘板连接电脑绘画有点迟钝怎么办 走路不小心滑了一下特尴尬怎么办 小孩子头撞了头发长不出来怎么办 小孩子头磕破了不长头发怎么办 晚上洗了冷水头早上头痛怎么办 头发洗了一天就油了怎么办 米诺地尔搽剂喷了头皮油怎么办