Select 使用不当引发的core,你应该知道的
排查一个死机问题,搞了好几天时间,最终确定原因;最终确定问题原因,在此分享一下;
第一步:常规根据core文件查看栈信息,gdb –c core xxxx
如下rip不正确,指令地址错乱,栈信息已破坏;在此基础上准确定位非常困难,但是仍可发现一些线索;
根据当前栈信息,大概寻找到怀疑的函数
查看整个栈上下信息,看有无怀疑的函数:
所以很有可能就是fetchNSAddrEv函数导致,需要重点关注;
更深入的细节,限于汇编不深入,比较难分析,不过可以有另外途径;
第二步:因为core是能复现出来,所以思路是重新编译版本,增加编译选项-fstack-protector
-fstack-protector:
启用堆栈保护,不过只为局部变量中含有 char 数组的函数插入保护代码。
-fstack-protector-all:
启用堆栈保护,为所有函数插入保护代码。
详细参见:http://www.cnblogs.com/napoleon_liu/archive/2011/02/14/1953983.html
复现后,栈结构如下:
这个栈结构,看着比较爽了; AsyncConnect返回时stackcheck检查栈溢出了;
第三步、审查代码,所以重点排查该函数:
先贴下代码
int CHttpHandler::AsyncConnect(const char * pszIpAddr, unsigned short usPort, float fSelectTimeout, const std::string& host)
{
if (strlen(pszIpAddr) > 16)
{
SetErrMsg("invalid ip format, pszIpAddr=%s", pszIpAddr);
return -1;
}
m_nSockFD= socket(AF_INET, SOCK_STREAM, 0);
m_fSelectTimeout= fSelectTimeout;
if (m_nSockFD < 0)
{
SetErrMsg("init socket error, m_nSockFD=%d", m_nSockFD);
return -2;
}
// set nonblock
int flags = fcntl(m_nSockFD, F_GETFL, 0);
if (fcntl(m_nSockFD, F_SETFL, flags | O_NONBLOCK) < 0)
{
close(m_nSockFD);
m_nSockFD = -1;
SetErrMsg("set sock nonblock error");
return -3;
}
// set server ip, port
struct sockaddr_in serv_addr;
socklen_t addr_len;
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
inet_aton(pszIpAddr, &serv_addr.sin_addr);
serv_addr.sin_port = htons(usPort);
addr_len = sizeof(serv_addr);
//memset(m_szIPAddr, 0, 17);
memset(m_szIPAddr,0,sizeof(m_szIPAddr));
if(!host.empty())
{
if(host.length()>sizeof(m_szIPAddr)-1)
{
SetErrMsg("hostName too long ,hostName=%s,hostLen=%d,max_len=%d\n",host.c_str(),host.length(),sizeof(m_szIPAddr));
return -9;
}
memcpy(m_szIPAddr, host.c_str(), host.length());
}
else
{
memcpy(m_szIPAddr, pszIpAddr, strlen(pszIpAddr));
}
/*linger m_sLinger;
m_sLinger.l_onoff = 1;
m_sLinger.l_linger = 0;
setsockopt(m_nSockFD, SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));*/
// connect
int nRetCode;
nRetCode = connect(m_nSockFD, (struct sockaddr *)&serv_addr, addr_len);
if (nRetCode < 0)
{
if (errno != EINPROGRESS)
{
SetErrMsg("connect error, errno=%d", errno);
close(m_nSockFD);
m_nSockFD = -1;
return -4;
}
}
if (nRetCode == 0)
{
;
}
else
{
//warning oss find select cause crash while select timeout
fd_set rset, wset;
FD_ZERO(&rset);
FD_SET(m_nSockFD, &rset);
wset = rset;
struct timeval tv;
tv.tv_sec = (int)m_fSelectTimeout;
long usec = int ((m_fSelectTimeout - (int)m_fSelectTimeout)*1000000 );
tv.tv_usec = usec;
nRetCode = select(m_nSockFD + 1, NULL, &wset, NULL, &tv);
if (nRetCode == 0)
{
// timeout
SetErrMsg("connect error: select timeout, select retcode=%d ", nRetCode);
close(m_nSockFD);
m_nSockFD = -1;
return -5;
}
if ( FD_ISSET(m_nSockFD, &wset))//FD_ISSET(m_nSockFD, &rset) ||
{
int error;
socklen_t len = sizeof(error);
if (getsockopt(m_nSockFD, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
{
SetErrMsg("connect error: getsockopt");
close(m_nSockFD);
m_nSockFD = -1;
return -6;
}
if (error)
{
SetErrMsg("connect error in select operation, error=%d", error);
close(m_nSockFD);
m_nSockFD = -1;
return -7;
}
}
else
{
SetErrMsg("connect error");
close(m_nSockFD);
m_nSockFD = -1;
return -8;
}
}
几个人审查代码,看了好久,没有发现该函数有什么问题;
第四步:检查日志及系统配置
进步查看日志发现有大量的select超时的打印,而且core掉时,必然在超时事件之后,此时怀疑select调用是否会出问题;因此,首先修改select为epoll调用进行测试,问题不能复现了;
五、如此,加深怀疑slecect相关处理
@福巴找到内核代码查看select相关实现;
当n值超过1024上限就会导致设置到数组之外,篡改掉内存;
FD_SET(m_nSockFD, &rset); 在m_nSockFD超过1024时,会导致rset数组越界,篡改后续内存;这也佐证了为什么select很多超时错误,因为m_nSockFD大小越界,没有落在select监听的套接字集合内;
从OSS环境上看,压测时,有大量连接并发处理,所以在压测时才最终发现该问题;
六、总结:
所有使用select系统调用的代码应提高警惕,系统使用的套接字超过默认配置的(1024,看系统配置)会导致这个潜在问题;
Select 使用不当引发的core,你应该知道的的更多相关文章
- jedis参数不当引发的问题总结
jedis参数不当引发dubbo服务线程池耗尽异常 现象:一个dubbo服务偶发性的出现个别机器甚至整个集群大量报线程池耗尽的问题.一开始对问题的处理比较粗暴,直接增加了10倍的线程数.但是问题依然偶 ...
- 【转载】select case break引发的血案
原文请看:select case break引发的血案 我也遇到了,浪费了一个多小时. 牢记: for { switch var1{ case "not match": go En ...
- delete数组引发的core分析
delete [] ptr 引发了singnal 6 abort的core错误,跟踪过程发现写入ptr大量数据,引发内存越界,破坏了new数组的尾部数据保护,导致delete的时候core. 问题分析 ...
- std::sort引发的core
#include <stdio.h> #include <vector> #include <algorithm> #include <new> str ...
- select for update引发死锁分析
本文针对MySQL InnoDB中在Repeatable Read的隔离级别下使用select for update可能引发的死锁问题进行分析. 1. 业务案例 业务中需要对各种类型的实体进行编号,例 ...
- 随机数使用不当引发的生产bug
前几天负责的理财产品线上出现问题:一客户赎回失败,查询交易记录时显示某条交易记录为其他人的卡号. 交易的链路如下: 出现该问题后,我们对日志进行了分析,发现主站收到的两笔流水号完全相同,然而主站却没有 ...
- mysql参数max_binlog_cache_size设置不当引发的血案
日常运维中的坑真是防不胜防,不一小心就遇到别人给你挖的坑.最近又遇到经验不足的DBA不知道从哪拷贝的配置文件(据说是当时参加某培训机构视频培训是资料里的模板,真的是误人子弟呀),其中把max_binl ...
- Web安全开发之验证码设计不当引发的撞库问题
感谢某电商平台安全工程师feiyu跟我一起讨论这个漏洞的修复.以往在安全测试的过程中后台经常存在验证码不失效果造成的撞库问题,甚至在一些银行或者电商的登录与查存页面同样存在这个问题,一旦造成撞库无论对 ...
- Proguard中optimize设置不当引发SimException
今天来说一下Proguard中关于optimize的问题.先上一张异常图片 最近项目重构,重新调整了各个组件之间的依赖关系.过程中,在项目Proguard这块卡住了,最开始还好,Proguard只是提 ...
随机推荐
- 【bzoj1821】[JSOI2010]Group 部落划分 Group Kruskal
题目描述 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗.只是,这一切都成为谜团了——聪 ...
- 【题解】51nod 1686第K大区间
成功的秘诀,在于克服自己看题解的冲动……[笑哭].自己A掉这题还是灰常开心的~ 以及爱死 two - pointer ! two - pointer 大法是真的好哇……这个题目有上一题的经验:求第\( ...
- [洛谷P4999]烦人的数学作业
题目大意:定义$f(x)$表示$x$每一个数位(十进制)的数之和,求$\sum\limits_{i=l}^rf(i)$,多组询问. 题解:数位$DP$,可以求出每个数字的出现个数,再乘上每个数字的大小 ...
- 一些技巧 && 常数优化 && 出现の错误
开坑原因 7.21 今天DTZ大爷教了我一个算欧拉函数的好方法......是质因数复杂度的 这让我想到,这些小技巧小idea,很多时候,可能就是考场上最致命.最一击必杀的"大招" ...
- [WC2008]游览计划 状压DP,斯坦纳树
---题面--- 题解: 这是一道斯坦纳树的题,用状压+spfa来解决 什么是斯坦纳树? 一开始还以为是数据结构来着,其实跟最小生成树很像,大致就是最小生成树只能在各个点之间直接相连,而斯坦纳树则允许 ...
- Android 打开照相机、获取相册图片、获取图片并裁减
一.调用照相机 注:surfaceView在当Activity不在前台的时候,会被销毁(onPause方法之后,执行销毁方法)当Activity回到前台时,在Activity执行onResume方法之 ...
- BZOJ5336:[TJOI2018]游园会——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5336 https://www.luogu.org/problemnew/show/P4590 小豆 ...
- POJ.1061 青蛙的约会 (拓展欧几里得)
POJ.1061 青蛙的约会 (拓展欧几里得) 题意分析 我们设两只小青蛙每只都跳了X次,由于他们相遇,可以得出他们同余,则有: 代码总览 #include <iostream> #inc ...
- NDK plugin来构建JNI项目(相对于手动构建)
http://blog.csdn.net/codezjx/article/details/8879670 1.添加ndk环境支持 Android Tools -> Add Native Supp ...
- wildcard ,notdir ,patsubst ,obj=$(dir:%.c=%.o)
Makefile中wildcard的介绍 在Makefile规则中,通配符会被自动展开.但在变量的定义和函数引用时,通配符将失效.这种情况下如果需要通配符有效,就需要使用函数“wildcard”,它的 ...