c - gdb 声称 realloc() 或 free() 损坏了内存,而 valgrind 声称非空终止数组运行结束......它是什么?

标签 c heap-memory realloc strcat corrupt

背景

我正在开发一个程序,其中一个从主线程分离的线程解析电子邮件日志并按 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);

strcpyrp->line写入分配的缓冲区之外。我在该函数中看到的唯一其他候选者是

msgs.msgs[rp->index].dump

如果不是以 0 结尾,则 strlen可以运行分配的缓冲区,并且 strcat之后可以再次在分配的内存之外写入。后者可以通过设置来避免

msgs.msgs[rp->index].dump[len0] = 0;

在重新分配之后和 strcat 之前.


设置rpNULL释放后

free(rp);
// prevent double free
rp = NULL;

毫无意义,因为 rp是局部变量,函数随后立即返回。传入的指针params仍然在调用者中保留旧地址(严格来说,它的值变得不确定,但实际上,这些位不会改变)。这开启了调用者认为指针仍然指向有效内存的可能性。

关于c - gdb 声称 realloc() 或 free() 损坏了内存,而 valgrind 声称非空终止数组运行结束......它是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15820719/

相关文章:

c - 8 位与 32 位指数偏差

c - 释放分配的内存 : realloc() vs. free()

memory-management - 使用 gcc/linux 就地重新分配

c - 我应该如何使用包含数组的结构进行 malloc/realloc?

c - 为什么 C 有逻辑和按位 ‘or’ 运算符?

c - 为什么基本算术运算符不需要 math.h 库

java - 在 64 位 Windows 中使用 32 位 Java

java - 空闲应用程序的堆大小随时间变小的含义

java - 如何使 Java 应用程序的内存高效?

c - 使用 fork() 函数使子进程和父进程共享内存