使用gdb调试内存重复释放导致的malloc_error_break错误崩溃

本文详细介绍了在使用Poco::Util::ServerApplication构建服务器application时,遇到内存泄漏问题的排查过程及解决方案。通过将Poco::Net::TCPServerConnectionFactory的管理方式从共享指针改为普通指针,成功避免了内存重复释放的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目前使用Poco::Util::ServerApplication构建服务器application,根据Poco官方文档自己扩展Poco::Net::TCPServerConnectionFactory,开启服务器tcp绑定监听。代码片段如下:

Poco::Net::ServerSocket cServerSocket(1300);
FxTcpConnectionFactory cFactory ("127.0.0.1"); 
Poco::Net::TCPServer cServer(&cFactory,cServerSocket);
cServer.start();

代码运行正常,可以正常监听到客户端连接,有一次在终端命令行直接用ctr+c结束进程,结果在服务器结束后给出一段崩溃提示。

ServerMaind(47292,0x7fff76465180) malloc: *** error for object 0x7fff5fbff6e8: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

字面上意思是被释放的指针未分配有效内存地址,这是典型的重复释放内存的问题。请出google大神,发现大部分是给出了xcode下如何设置malloc_error_break 符号,我用的是codelite,并不适用,不管他们了,直接进入执行程序所在目录,执行gdb调试命令:

$gdb ./ServerMaind // 开始调试该程序

(gdb) b malloc_error_break // 设置malloc_error_break

(gdb) r // 在调试器中运行ServerMaind,又出同样的错误了,已经被gdb捕捉到了,object 0x7fff5fbff6e8 释放不正常

(gdb) backtrace // 调出崩溃现场的程序调用堆栈

#0  0x00007fff8e58c5b8 in malloc_error_break ()
#1  0x00007fff8e58d972 in free ()
#2  0x0000000100028ca8 in FxTcpConnectionFactory::~FxTcpConnectionFactory (this=0x7fff5fbff6e8) at FxTcpConnectionFactory.cpp:19
#3  0x000000010002afea in Poco::ReleasePolicy<Poco::Net::TCPServerConnectionFactory>::release (pObj=0x7fff5fbff6e8) at SharedPtr.h:90
#4  0x000000010002c9bc in Poco::SharedPtr<Poco::Net::TCPServerConnectionFactory, Poco::ReferenceCounter, Poco::ReleasePolicy<Poco::Net::TCPServerConnectionFactory> >::release (this=0x100e0bc80) at SharedPtr.h:404
#5  0x000000010002ca1e in Poco::SharedPtr<Poco::Net::TCPServerConnectionFactory, Poco::ReferenceCounter, Poco::ReleasePolicy<Poco::Net::TCPServerConnectionFactory> >::~SharedPtr (this=0x100e0bc80) at SharedPtr.h:159
#6  0x00000001001feeb0 in Poco::Net::TCPServerDispatcher::~TCPServerDispatcher (this=0x100e0bb70) at TCPServerDispatcher.cpp:99
#7  0x00000001001fe3bb in Poco::Net::TCPServerDispatcher::release (this=0x100e0bb70) at TCPServerDispatcher.cpp:115
#8  0x00000001001f234b in Poco::Net::TCPServer::~TCPServer (this=0x7fff5fbff648) at TCPServer.cpp:74
#9  0x0000000100029c23 in FxTcpServerMng::main (this=0x100e09aa0, args=@0x100e09ae0) at FxTcpServerMng.cpp:134
#10 0x0000000100212938 in Poco::Util::Application::run (this=0x100e09aa0) at Application.cpp:307
#11 0x0000000100247c2a in Poco::Util::ServerApplication::run (this=0x100e09aa0) at ServerApplication.cpp:117
#12 0x0000000100247a5b in Poco::Util::ServerApplication::run (this=0x100e09aa0, argc=1, argv=0x7fff5fbffae8) at ServerApplication.cpp:628
#13 0x0000000100001497 in main (argc=1, argv=0x7fff5fbffae8) at main.cpp:15
(gdb)

罪魁祸首找到了,原来Poco::Net::TCPServerConnectionFactory用的是共享指针方式来管理内存,而我直接FxTcpConnectionFactory cFactory ("127.0.0.1"),超出作用域就自己释放了,导致程序推出的时候重复释放内存,程序改成如下:

Poco::Net::ServerSocket cServerSocket(1300);
FxTcpConnectionFactory pFactory = new  FxTcpConnectionFactory ("127.0.0.1"); 
Poco::Net::TCPServer cServer(pFactory,cServerSocket);
cServer.start();

再运行后退出,果然正常了。


使用GDB进行内存泄漏调试的基本步骤如下: 1. 在编译时加入 -g 选项,以便GDB能够读取符号表信息。 2. 启动程序并在GDB中设置断点,以便在程序运行到此处时停止。例如,可以在程序的 main 函数中设置断点。 3. 在GDB中运行程序,让程序执行到断点处停止。 4. 使用GDB内存调试工具来检查程序是否有内存泄漏。例如,可以使用 GDB 的 `valgrind` 命令来检查程序内存使用情况。 5. 如果发现内存泄漏,使用GDB调试工具找出泄漏的位置和原因,并修复程序中的错误。 下面是一个简单的示例,展示了如何使用GDB和 `valgrind` 来检查内存泄漏: ```c++ #include <stdlib.h> int main() { int* p = (int*) malloc(sizeof(int)); *p = 10; return 0; } ``` 假设上述代码保存在文件 `test.c` 中,使用以下命令编译: ``` gcc -g -o test test.c ``` 然后使用以下命令启动GDB: ``` gdb test ``` 在GDB中设置断点: ``` break main ``` 运行程序: ``` run ``` 程序会在 `main` 函数中断下来。接下来,使用 `valgrind` 来检查内存泄漏: ``` valgrind ./test ``` `valgrind` 会输出以下信息: ``` ==2833== Memcheck, a memory error detector ==2833== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==2833== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==2833== Command: ./test ==2833== ==2833== ==2833== HEAP SUMMARY: ==2833== in use at exit: 4 bytes in 1 blocks ==2833== total heap usage: 1 allocs, 0 frees, 4 bytes allocated ==2833== ==2833== LEAK SUMMARY: ==2833== definitely lost: 4 bytes in 1 blocks ==2833== indirectly lost: 0 bytes in 0 blocks ==2833== possibly lost: 0 bytes in 0 blocks ==2833== still reachable: 0 bytes in 0 blocks ==2833== suppressed: 0 bytes in 0 blocks ==2833== Rerun with --leak-check=full to see details of leaked memory ==2833== ==2833== For counts of detected and suppressed errors, rerun with: -v ==2833== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) ``` 可以看到,`valgrind` 检测到了一个内存泄漏,程序在退出时仍然有4字节的内存没有释放。现在,我们可以使用GDB来找出哪里出了问题: ``` gdb test ``` 在GDB中运行 `valgrind` 检测内存泄漏: ``` run --vgdb=yes ``` GDB会在程序启动后等待连接到 `valgrind`。在另一个终端窗口中,运行以下命令连接到GDB: ``` vgdb ``` 然后在GDB中打印出内存泄漏的地址: ``` monitor leak_check -show-reachable=yes ``` GDB会输出以下信息: ``` ==2833== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==2833== at 0x4C2AB80: malloc (vg_replace_malloc.c:299) ==2833== by 0x40054A: main (test.c:4) ``` 可以看到,内存泄漏发生在第4行,也就是 `malloc` 函数调用的位置。现在,我们可以检查这个函数调用的原因,并修复程序中的错误
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值