背景
我正在开发一个程序,其中一个从主线程分离的线程解析电子邮件日志并按 QID(每条消息的唯一 ID)组织每个条目。
问题
该程序一直在工作,直到我重新组织它,这样我就可以在读取日志文件时开始解析每一行,而不是首先将整个日志文件加载到内存中。该程序将在如下所示的代码片段中使用 SIGABRT(稍微简化,但演示了相同的问题)。
调试结果
gdb 将声称它是(取决于运行)realloc/free 无效大小或 realloc/free 损坏的内存,而 valgrind 始终声称非空终止数组导致运行关闭并损坏堆(我认为这是更有可能是这种情况,但找不到问题)。 (如果您希望我分享 valgrind 或 gdb 的原始输出,请告诉我)。
void *parseMessageAndMatch(void *params) {
// get params passed in from parent thread
parse_params *rp = (parse_params *)params;
// len0: length of log dump for current QID
// len1: length of log dump after current buffer is appended
int len0, len1;
// tmp char pointer for log dump
char *tmp;
// 1. increase/allocate memory for log dump and append line buffer
// get length of current log dump (0 if NULL)
// dump is of type char* and contains the log lines pertaining to a certain QID
len0 = (!msgs.msgs[rp->index].dump) ? 0 : strlen(msgs.msgs[rp->index].dump);
// get length of log dump after current line buffer is appended
// rp->len contains the strlen of the line buffer
len1 = len0 + rp->len + 1;
// allocate space for tmp log dump
// lock becaus msgs is a global variable and there is more than one thread
pthread_mutex_lock(rp->mutex);
if ((tmp = realloc(msgs.msgs[rp->index].dump, sizeof(*tmp)*len1)) == NULL) {
printf("Cannot allocate memory for log dump.\n");
exit(-1);
}
// update pointer
msgs.msgs[rp->index].dump = tmp;
// set tmp to null
tmp = NULL;
// if original buffer was empty, zero it out for safety
if (len0 == 0)
bzero(msgs.msgs[rp->index].dump, sizeof(char)*len1);
// rp->line is malloc'ed then bzero'ed and strcpy'ed to contain the log line read from file
strcat(msgs.msgs[rp->index].dump, rp->line);
msgs.msgs[rp->index].dump[len1-1] = '\0'; // add null terminator
pthread_mutex_unlock(rp->mutex);
// more parsing code is here but was commented out during my debug process
// so I have omitted it from this code snippet
// free line buffer
free(rp->line);
// set to null to prevent double free
rp->line = NULL;
// free params
free(rp);
// prevent double free
rp = NULL;
}
编辑
在下面的答案中进行了更正。
最佳答案
msgs.msgs[rp->index].dump[len1] = '\0'; // add null terminator
之后
realloc(msgs.msgs[rp->index].dump, sizeof(*tmp)*len1)
是越界写入。最后一个有效索引是 len1 - 1
.
由于代码在修复后仍然中止,可能是这样的
// rp->line is malloc'ed then bzero'ed and strcpy'ed to contain the log line read from file
strcat(msgs.msgs[rp->index].dump, rp->line);
strcpy
至rp->line
写入分配的缓冲区之外。我在该函数中看到的唯一其他候选者是
msgs.msgs[rp->index].dump
如果不是以 0 结尾,则 strlen
可以运行分配的缓冲区,并且 strcat
之后可以再次在分配的内存之外写入。后者可以通过设置来避免
msgs.msgs[rp->index].dump[len0] = 0;
在重新分配之后和 strcat
之前.
设置rp
至NULL
释放后
free(rp);
// prevent double free
rp = NULL;
毫无意义,因为 rp
是局部变量,函数随后立即返回。传入的指针params
仍然在调用者中保留旧地址(严格来说,它的值变得不确定,但实际上,这些位不会改变)。这开启了调用者认为指针仍然指向有效内存的可能性。
关于c - gdb 声称 realloc() 或 free() 损坏了内存,而 valgrind 声称非空终止数组运行结束......它是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15820719/