問題描述:
使用hiredisCluster 運行報錯,錯誤截圖如下:
通過分析hiredis源代碼發現,在net.c的源文件中283行代碼:
1 c->tcp.host = strdup(addr);
strdup中申請內存,並將addr內容拷貝到新申請的內存中,並返回新申請內存的指針。
strdup函數實現,來自百度百科:
1 char * __strdup (const char *s) 2 { 3 size_t len = strlen (s) + 1; 4 void *new = malloc (len); 5 if (new == NULL) 6 return NULL; 7 return (char *) memcpy (new, s, len); 8 }
分析:這部分代碼在申請內存后沒有進行初始化,直接就拷貝數據,感覺這樣數據最后會缺少一個'\0',會給后面打印輸出計算長度(strlen)等造成影響,導致出錯。
這部分內存申請后在hiredis.c的redisFree函數中釋放(11行(626)),函數代碼如下:
1 void redisFree(redisContext *c) { 2 if (c == NULL) 3 return; 4 if (c->fd > 0) 5 close(c->fd); 6 if (c->obuf != NULL) 7 sdsfree(c->obuf); 8 if (c->reader != NULL) 9 redisReaderFree(c->reader); 10 if (c->tcp.host) 11 free(c->tcp.host); 12 if (c->tcp.source_addr) 13 free(c->tcp.source_addr); 14 if (c->unix_sock.path) 15 free(c->unix_sock.path); 16 if (c->timeout) 17 free(c->timeout); 18 free(c); 19 }
在第10行檢查內存不為空,但是釋放的時候報“double free”的錯誤。開始一直沒搞明白為什么,后面和組內同事溝通,發現是平台內部使用了組內的malloc和free函數替換了系統“malloc”和“free”,導致在strdup中使用系統的“malloc”,而在hiredis.c中,的free為平台提供的標准函數。但是通過斷下來的堆棧看,free使用的操作系統的,這種推斷不對。后來和開發平台的同時討論並通過實驗證實應該是由於自己編寫的內存替換函數引起,去除該函數后程序運行正常。