【问题标题】:valgrind - Address ---- is 0 bytes after a block of size 8 alloc'dvalgrind - 地址 ---- 在大小为 8 的块分配后为 0 个字节
【发布时间】:2023-03-03 00:50:01
【问题描述】:

首先,我知道有人问过类似的问题。但是,我想对真正原始的 C 数据类型提出一个更一般的简单问题。就是这样。

main.c 中,我调用了一个函数来填充这些字符串:

int
main (int argc, char *argv[]){

    char *host = NULL ;
    char *database ;
    char *collection_name;
    char *filename = ""; 
    char *fields = NULL;
    char *query = NULL;
    ...

    get_options(argc, argv, &host, &database, &collection_name, &filename, 
                &fields, &query, &aggregation);

get_options

if (*filename == NULL ) {
   *filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+4);
    strcpy(*filename, *collection_name);
    strcat(*filename, ".tde");  # line 69 
}

我的程序运行良好,但 Valgrind 告诉我我做错了:

==8608== Memcheck, a memory error detector
==8608== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==8608== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==8608== Command: ./coll2tde -h localhost -d test -c test
==8608== 
==8608== Invalid write of size 1
==8608==    at 0x403BE2: get_options (coll2tde.c:69)
==8608==    by 0x402213: main (coll2tde.c:92)
==8608==  Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd
==8608==    at 0x4C28BED: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8608==    by 0x4C28D6F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8608==    by 0x403BBC: get_options (coll2tde.c:67)
==8608==    by 0x402213: main (coll2tde.c:92)

你能解释错误Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd吗? 我该如何解决这个问题?

【问题讨论】:

  • 不管怎样,我发现这条错误消息令人困惑,因为我误解了“之后”的含义。我认为这意味着“在分配块之后”,但当然它实际上意味着“在分配块之后的内存中”。换句话说:Address 0x... appears immediately (0 bytes) after an alloc'd block of size 8

标签: c linux valgrind


【解决方案1】:

strcpy 添加一个空终止符'\0'。您忘记为其分配空间:

*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);

您需要为 5 个字符添加空格:".tde" 后缀为 4 个,'\0' 终止符多一个。您当前的代码只分配了 4 个,因此最后一次写入是在您为新文件名分配的块之后的空间中完成的(即它之后的 0 个字节)。

注意:您的代码有一个常见问题 - 它将realloc 的结果直接分配给正在重新分配的指针。 realloc 成功时这很好,但失败时会造成内存泄漏。修复此错误需要将realloc 的结果存储在一个单独的变量中,并在将值分配回*filename 之前检查NULL

char *tmp = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
if (tmp != NULL) {
    *filename = tmp;
} else {
    // Do something about the failed allocation
}

直接分配给*filename 会造成内存泄漏,因为*filename 一直指向下方的指针会在失败时被覆盖,变得不可恢复。

【讨论】:

  • 哎呀!我以前试过这个,出于某种原因我删除了它。所以我需要在这里更加小心!但为什么是含糊的英语?如果我新创建的字符串大 1,为什么 valgrind 会说: 0 bytes after ... ?
  • 好的,你已经看到了。所以,0 bytes after 是 Valgrind 开发人员用简单的英语告诉我的方式:“它是相邻的”,或者“直接在它之后”。
  • @Oz123: 0 bytes after42 bytes after 一样正确,不是吗?
  • @Oz123 假设块从 0x8000 开始,长度为 8 个字节。那么块的最后一个有效地址将是 0x8007,而 0x8008 将是它之后的第一个无效地址。当 valgrind 在 0x8008 处看到写入时,它会将其报告为对非法块的初始字节的写入,就好像它是一个字节数组一样,并且它使用从零开始的表示法来报告偏移量。
  • @Ac3_DeXt3R "Similar" 不够具体。提出一个新问题,并提供所有详细信息。
【解决方案2】:

我刚刚收到此消息是因为我更改了一个类(添加了一个字段,因此我更改了它的大小),并且没有重新构建包含标题的所有源。所以一些模块仍然尝试使用旧的尺寸。

【讨论】:

    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 2015-03-17
    • 2018-08-21
    • 2012-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多