背景:工作中替换了一个sdk库,原因是库里添加了一个接口,对应声明接口的头文件也替换了。但在实际使用过程中,程序崩溃,抛出了异常std::__throw_length_error。程序生成了core文件,使用gdb调试即可,如下:
1,gdb core文件
2,打印出所有调用堆栈
set height 0 表示打印不限制高度,gdb打印满屏时会暂停输出,需要手动回车才往下打印,此项设置后一次性全部打印。
thread apply all bt 所有线程执行bt操作,方便找出异常的线程,因为当前打印的线程并不一定是异常线程,如:
gdb中异常线程号为18,t 18切换到此线程,打印调用堆栈。应用程序接口uploadRecord(), 再往下调用就到sdk库里,如sendExecuteRecord()。目前从bt打印可以看出,是访问了非法地址导致的异常,如图中的“error: Cannot access memory at address 0x2c”
3,进入栈帧查看相关信息
切换栈帧
查看函数入参的值:
使用set print pretty 使得打印如结构体或数组时更直观(即每个成员占一行)。
至此找到了异常点,可能是成员赋值导致的异常。查看源码,且添加打印信息,此成员赋值是正常的,其中string的地址是正常的,如下:
这就更奇怪了,调用前地址是正常的,调用后地址变异常了,为何? 能想到的就是踩内存,这个成员string的内存被踩了。把堆栈打印发给维护sdk库的同事一看,说是头文件未更新,sdk库里的这个结构体成员有变动,但我的app里使用的还是老的头文件,
这样sdk库里使用此结构体时,取到的成员string的地址可能就不是传入的地址,结构体差异如下:
最新头文件为左侧,我使用的是右侧头文件,成员变量不一致异常访问异常。更新头文件后,一切正常。
总结:
在使用到外部库时切记同步更新头文件。