1、問題現(xiàn)象
線上服務每隔一個多月會出現(xiàn)一次core,core在一個多線程庫的queue里面。
queue使用循環(huán)數(shù)組實現(xiàn),里面主要有以下數(shù)據(jù)成員:
{size_t len;/*數(shù)組長度*/ olatile size_t head;/*隊列頭*/ volatile size_t tail;/*隊列尾*/ T* array;/*數(shù)組指針*/}
core的調用棧位置:array[tail] = std::move(val); core在向隊列尾添加消息的語句。
dmesg信息:segfault at 2872fa0 ip 000000000047e9e3 sp 00007fcc94ffd360 error 4,非法地址是2872fa0,core的位置是47e9e3。
2、使用objdump命令將可執(zhí)行文件反匯編。
array[tail] = std::move(val);語句對應的匯編代碼如下:
%rbx存的是queue對象,(%rbx)對應qlen,0x8(%rbx)對應head,0x10(%rbx)對應tail,0x18(%rbx)對應array。
%rax中存的是無效地址2872fa0,%rax = array + 8*tail。
3、查看core文件中寄存器的內容,使用info registers命令。
4、查看%rbx指向的內存的內容,從中可以得到queue中成員變量的值,使用x命令。
可以看出:tail = 4712592,array = 4713248,array + 8 * tail = 4713248 +? 8 * 4712592 = 42413984 = 2872fa0,正好是引起core的無效地址。
進一步發(fā)現(xiàn) qlen = 4708768,head = 4708864,發(fā)現(xiàn)可疑的地方,首先qlen沒有這么大,我們設置的qlen應該等于遠小于這個值,另外qlen也不應該小于head和tail,這時候考慮可能由兩種情況導致的:(1)queue對象的內容被飛踩了(2)queue對象是不是獲取錯了。考慮到queue對象被飛踩定位比較難,所以先檢查queue對象獲取的是否正確。
5、進一步檢查代碼,發(fā)現(xiàn)多線程庫中會有多個Consumer,每個Consumer對應一個queue對象,將一個消息發(fā)送給哪個queue是由我們業(yè)務根據(jù)輪詢選擇的,輪詢的代碼(worker++%worker_num),而worker定義成int型,int型當加到最大值后會出現(xiàn)翻轉變成負數(shù),對負數(shù)取余還是負數(shù),將一個負數(shù)付給一個ulong型就會變成一個很大的數(shù),導致獲取的queue對象不正確,最終導致core。
6、進一步驗證,用f命令進入業(yè)務層代碼的frame,用info locals命令查看worker變量的值。
worker為負數(shù),驗證了問題。