ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【segmentation fault】 智能指针异常崩溃

2022-03-25 17:31:52  阅读:239  来源: 互联网

标签:map segmentation context fault 代码 io msg apc 指针


 1 std::map<sio_t*, std::shared_ptr<Contextapc>> map_apc_context_;
 2 
 3 // 客户端读事件
 4 static void on_apc_recv(sio_t *io, void *buf, int readbytes)
 5 {
 6     // 获取客户端上下文
 7     std::shared_ptr<Context> context = Server::Instance()->ApcContextByIO(io);
 8     if (context != nullptr)
 9     {
10         if (readbytes > 0)
11         {
12             // 接收客户端数据
13             context->Receive(buf, readbytes);
14         }
15         else
16         {
17             // 客户端异常
18             LOGW("[ on_apc_recv ] peer (%d) closed. len: %d", sio_fd(io), readbytes);
19             Server::Instance()->RemoveApcContext(io);
20         }
21     }
22     else
23     {
24         LOGW("[ on_apc_recv ] unknown context(%d). buf: %s, len: %d", sio_fd(io), (char *)buf, readbytes);
25     }
26 }
27 
28 // 连接事件
29 static void on_apc_connected(sio_t *io)
30 {
31     // 设置读事件
32     sio_setcb_read(io, on_apc_recv);
33     sio_read(io);
34     
35     // 调用服务处理连接方法
36     Server::Instance()->onapcConnected(io);
37 }
38 
39 // 获取客户端连接上下文
40 std::shared_ptr<Context> Server::ApcContextByIO(sio_t *io)
41 {
42     auto it = map_apc_context_.find(io);
43 
44     if (it != map_apc_context_.end())
45     {
46         return it->second;
47     }
48     else
49     {
50         return NULL;
51     }
52 }
53 
54 // 连接处理方法
55 void Server::onapcConnected(sio_t *io)
56 {
57     // 创建智能指针
58     std::shared_ptr<Contextapc> context = std::make_shared<Contextapc>(io); 
59     // 对象保存在 map 数据结构中
60     map_apc_context_[io] = context;
61     LOGI("[ onapcConnected ] fd: %d, size: %d", sio_fd(io), map_apc_context_.size());
62 }

前几天压测服务代码,出现了崩溃,崩溃行数在13行

context->Receive(buf, readbytes);

1.因为是服务代码,信号11都已经被捕获了,只能看一些堆栈信息,错误定位在这一行,我的第一反应是智能指针 context 里管理的对象是空的,

因此我注释了信号捕捉函数,得到coredump文件,通过分析coredump文件,context 管理的指针不是 NULL,我认为应该是 context 管理的对象被破坏了。--分析问题

2.于是我仔细阅读了附近的代码,代码基本都是C++写的,内存操作的地方不多,没能看出问题。 --代码阅读

3.codereview上无法看出问题,只能通过分析服务运行轨迹,看是否有思路。我在崩溃链路上加了很多日志,发现 on_apc_connected --> onapcConnected --> on_apc_recv 直接就崩溃了,当时很疑惑,因为刚刚建立链接,收到第一个报文就崩溃了,任何业务代码都没有执行,陷入僵局。   --业务分析

4.继续复读代码,猜测是不是多线程场景下,该实例先被从A线程 map_apc_context_ 删除了,但是B线程刚好使用,因为我并没有对 map_apc_context_ 加锁保护,但是我90%确定这是一个单线程逻辑,不存在上述情况,但是我还是抱着侥幸心理,在使用 context 对象之前,判断了一下 context 是否有效,结果仍是是崩溃。  --怀疑标准库

5.因为本人没有读过智能指针源码,我开始怀疑是智能指针有BUG,因此我修改代码,不直接使用 context 调用 Receive 方法,而是取出 context 管理的实例来调用 Receive 方法,然后崩溃的断点进入 Receive 函数内部一个使用成员属性的地方,这个崩溃信息很明确告诉我的确是 context 管理的对象出现问题了。   --确定崩溃的根本原因

6.我继续复读代码,确信接收报文这段业务逻辑是没有问题的,那么只剩下一个选项,肯定是某个地方内存越界了,影响了 map_apc_context_ 这个对象,此时阅读代码的重点不再是连接的创建接收报文逻辑,而是转向 context 实力内部业务处理逻辑,发现以下代码

if (msg->type & MSG_TYPE_TEST_BIT)
{
    char buff[128] = { 0 };
    sprintf(buff, "debug message;");
    memcpy(apc_msg_body(msg) + strlen(apc_msg_body(msg)), buff, strlen(buff));
}

这里的msg本身的长度就是 apc_msg_body(msg) + strlen(apc_msg_body(msg)),这段代码居然还要在后面拼接上一段,很有可能内存泄漏了,但是我的消息码并不是MSG_TYPE_TEST_BIT,我认为不可能进入这段逻辑。我抱着试试看的心态将这段代码注释了,准备再次进行测试(因为只有在压测环境下才能复现问题,我自己并没有相应的环境,所以改完代码到测试阶段还有点时间)。就在我改完代码,我突然想到当时为了做内存管理,使用了jemalloc,是不是因为jemalloc做了内存管理,导致实际的内存泄漏被滞后了呢?于是我回滚代码,先将jemalloc注释掉,然后再进行压测,发现崩溃的地方就是上面分析的那块代码,因为先前同事使用了 & 操作,并不完全等同于== ,而我新定义的消息码刚好就能进入这段逻辑,从而导致了崩溃。    --找到方案

 

总结:

    a. 出现 segmentation fault 肯定需要看附近的代码,如果附近的代码没有问题,就要考虑是否是别的地方的内存越界影响了崩溃断点

    b. 分析segmentation fault 绝对不能开 jemalloc

    c. 绝对不要怀疑第三方标准库

 

标签:map,segmentation,context,fault,代码,io,msg,apc,指针
来源: https://www.cnblogs.com/zhanggaofeng/p/16055809.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有