问题描述:
使用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使用的操作系统的,这种推断不对。后来和开发平台的同时讨论并通过实验证实应该是由于自己编写的内存替换函数引起,去除该函数后程序运行正常。