c - 从 valgrind 读取大小为 1 的内容无效

标签 c memory-leaks valgrind

修复内存泄漏后,valgrind 显示如下一堆错误,我不知道如何修复。是因为我释放了比我需要的更多的空间吗?

第 39 行:

root = importTree(*(argv+1));

第 72 行:

 printf("Result found for %d:\n       city: %s\n       state:%s\n", zip, new->city, new->state);

Node *importTree(char *filename) {
    Node *root = NULL;
    FILE *fp = fopen(filename, "r");

    if (!fp) {
        printf("Error opening file.\n");
        return NULL;
    }

    while (!feof(fp)) {
        Node *new = malloc(sizeof(Node));
        if (!new) {
            printf("Failed to allocate memory. Ending read.\n");
            exit(1);
            fclose(fp);
        }
        new->city = malloc(sizeof(char) * MAXCITYNAME);
        if (!(new->city)) {
            printf("Failed to allocate memory. Ending read.\n");
            exit(1);
            fclose(fp);
        }
        new->left = NULL;
        new->right = NULL;
        char *line = malloc(sizeof(char) * MAXLINELENGTH);
        if (!line) {
            printf("Failed to allocate memory. Ending read.\n");
            exit(1);
            fclose(fp);
        }
        if (fgets(line, MAXLINELENGTH, fp) == NULL) {
            if (!feof(fp)) {
                printf("File reading ended prematurely. Check for errors in the file.\n");
                exit(1);
                fclose(fp);
            }
            free(new->city);
            free(line);
            free(new);
            fclose(fp);
            break;
        }
        char *tmp = strtok(line, ",");
        new->zipCode = atoi(tmp);
        tmp = strtok(NULL, ",");
        strcpy(new->city, tmp);
        new->city[strlen(tmp) + 1] = '\0';
        tmp = strtok(NULL, ",");
        strcpy(new->state, tmp);
        new->state[2] = '\0';
        root = addNode(root, new);
        if (!root) {
            printf("Root of tree is still NULL! Ending read.\n");
            exit(1);
        }
        free(line);
        free(new->city); \\this is the line 220
    }
    fclose(fp);
    return root;
}

这是 valgrind 的输出:

Invalid read of size 1
==7879==    at 0x517FAB4: vfprintf (vfprintf.c:1635)
==7879==    by 0x5188C98: printf (printf.c:34)
==7879==    by 0x400BBD: main (hw3.c:72)
==7879==  Address 0x5657a30 is 0 bytes inside a block of size 30 free'd
==7879==    at 0x4C2AD17: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==7879==    by 0x40103F: importTree (hw3.c:220)
==7879==    by 0x400A31: main (hw3.c:39)
==7879==
==7879== Invalid read of size 1
==7879==    at 0x51ADA99: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1342)
==7879==    by 0x517FA6C: vfprintf (vfprintf.c:1635)
==7879==    by 0x5188C98: printf (printf.c:34)
==7879==    by 0x400BBD: main (hw3.c:72)
==7879==  Address 0x5657a37 is 7 bytes inside a block of size 30 free'd
==7879==    at 0x4C2AD17: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==7879==    by 0x40103F: importTree (hw3.c:220)
==7879==    by 0x400A31: main (hw3.c:39)
==7879==
==7879== Invalid read of size 1
==7879==    at 0x51ADAAC: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1342)
==7879==    by 0x517FA6C: vfprintf (vfprintf.c:1635)
==7879==    by 0x5188C98: printf (printf.c:34)
==7879==    by 0x400BBD: main (hw3.c:72)
==7879==  Address 0x5657a36 is 6 bytes inside a block of size 30 free'd

最佳答案

为什么在树中插入节点后,free new 结构的 city 成员?它属于结构,当你释放树时它会被释放两次。

您的代码中还有其他问题:

  • while (!feof(fp)) 总是错误的。在您的情况下,只需使用 for(;;) 永远运行并在 fgets() 在文件末尾失败时优雅地退出循环。
  • 你不应该使用 new 作为标识符,它会混淆代码着色器(和读者),因为它是 C++ 中的关键字。只需将其称为 nodenp
  • new->city[strlen(tmp) + 1] = '\0'; 充其量是无用的,可能会导致缓冲区溢出。
  • 确实,我们不知道您的数组大小的值,但您在调用 strcpy() 复制行 block 之前没有检查大小。这可能会调用未定义的行为。
  • 您应该改为使用 strdup() 为行片段分配正确的大小并通过一个简单的步骤复制内容。
  • 类似地,在成功的 fgets() 之后 分配节点将简化错误情况。
  • 您没有检查 strtok() 的返回值。无效的文件内容可能会导致返回值为 NULL,调用未定义的行为而不是优雅的 fatal error 。

这是一个更简单的更正版本:

Node *importTree(const char *filename) {
    char line[MAXLINELENGTH];
    Node *root = NULL;
    FILE *fp = fopen(filename, "r");

    if (!fp) {
        printf("Error opening file.\n");
        return NULL;
    }

    while (fgets(line, MAXLINELENGTH, fp) != NULL) {
        Node *node = malloc(sizeof(Node));
        if (!node) {
            printf("Failed to allocate memory. Ending read.\n");
            fclose(fp);
            exit(1);
        }
        new->left = NULL;
        new->right = NULL;
        char *tmp = strtok(line, ",");
        if (!tmp) {
            printf("Invalid file contents. Ending read.\n");
            fclose(fp);
            exit(1);
        }
        new->zipCode = atoi(tmp);
        tmp = strtok(NULL, ",");
        if (!tmp) {
            printf("Invalid file contents. Ending read.\n");
            fclose(fp);
            exit(1);
        }
        node->city = strdup(tmp);
        if (!(new->city)) {
            printf("Failed to allocate memory. Ending read.\n");
            fclose(fp);
            exit(1);
        }
        tmp = strtok(NULL, ",");
        if (!tmp) {
            printf("Invalid file contents. Ending read.\n");
            fclose(fp);
            exit(1);
        }
        tmp[2] = '\0';
        node->state = strdup(tmp);
        if (!node->state) {
            printf("Failed to allocate memory. Ending read.\n");
            fclose(fp);
            exit(1);
        }
        root = addNode(root, node);
        if (!root) {
            printf("Root of tree is still NULL! Ending read.\n");
            fclose(fp);
            exit(1);
        }
    }
    if (!feof(fp)) {
        printf("File reading ended prematurely. Check for errors in the file.\n");
        fclose(fp);
        exit(1);
    }
    fclose(fp);
    return root;
}

关于c - 从 valgrind 读取大小为 1 的内容无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38516085/

相关文章:

c - 如何修复我的 pthread 代码遇到的此错误?

c++ - 在 main() 之前在编译时或运行时初始化函数指针的全局数组

javascript - 管理 Javascript 内存中变量的最佳方法是什么

C++:调试引用计数系统中的内存泄漏

c - 为什么 valgrind 报告此 mini-xml 代码中存在泄漏?

c - 在 C 中的 char 数组的前半部分中查找每隔一个字符的程序

c - dup2 重定向 printf 失败?

language-agnostic - 当需要极高的可靠性时,如何处理动态内存分配?

valgrind - 为内存泄漏生成抑制

c++ - 检测到 'memory leak' 时,valgrind 中的实际指针是什么?