程序异常退出调试

时间:2022-09-18 22:53:44

这周遇到一个非常奇怪的事,程序在压力测试的时候会莫名奇怪的挂掉,但是调试时却发现情况也是很诡异。使用GDB打印调用栈后发现,函数调用栈里的this指针指向的值不对劲。

 CRedisClient::connect (this=0x603, 
    ip=<error reading variable: Cannot access memory at address 0x1>, port=4, 
    timeout=-1956863078)

不仅如此,所有参数的值都不对。当时就在想,是不是某个地方的操作导致内存溢出了,覆盖了栈内容,于是就想顺着调用栈一直往上找,看看是在哪个函数调用处出的问题,然而却发现找到第一个调用栈时,this指针和函数参数还是不对,更加让人不解的是,所有的调用栈里,使用info locals查看变到的局部变量的值都是正确的,这就表明,程序堆栈并没有完全被破坏掉。而且,某些局部变量的值是从函数参数里算出来的,但是info args查看参数就有问题,info locals查看局部变量就有问题。通过查找资料,大概明白了可能原因,由于现在的CPU都拥有数量较多的寄存器,于是,一般的参数传递都是使用寄存器来进行的,http://blog.csdn.net/dayancn/article/details/51328959中有介绍到:

X86-64有16个64位寄存器,分别是:%rax,%rbx,%rcx,%rdx,%esi,%edi,%rbp,%rsp,%r8,%r9,%r10,%r11,%r12,%r13,%r14,%r15。其中:
%rax 作为函数返回值使用。
%rsp 栈指针寄存器,指向栈顶
%rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函数参数,依次对应第1参数,第2参数。。。
%rbx,%rbp,%r12,%r13,%14,%15 用作数据存储,遵循被调用者使用规则,简单说就是随便用,调用子函数之前要备份它,以防他被修改
%r10,%r11 用作数据存储,遵循调用者使用规则,简单说就是使用之前要先保存原值

于是我就查看了一下rdi, rsi, rdx几个寄存器的值,果然这几个寄存器的值全都有问题,怪不得所有的参数都看不见呢,估计是在什么地方被写坏了。由于对寄存器的了解不是很深入,只好放弃core文件的调试,直接开着gdb 运行程序进行压测吧。这一开,发现

程序异常退出调试

满屏的创建新线程提示啊,查看了下进程的线程数目,3000多呢,有时候能过万。这太不正常了,不是使用线程池的吗?联想到以前20路压测时没出过问题,在100路压测时就有了问题,应该可能是跟线程数量过多有关,于是查找线程池相关的代码,果然是有问题的,

只有增加线程,没有删除线程,怪不得线程数量会一直增加。

然而还是没有找到程序异常退出的直接原因,但是得先将线程池这个地方的数量控制加上去再进行测试,这个问题还远没有结束,看来还得继续找下去。。。