valgrind - Address ----在大小为8的块之后为0字节

Oz1*_*123 23 c linux valgrind

首先,我知道有类似的问题.但是,我希望有一个更普遍的简单问题,真正原始的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);
Run Code Online (Sandbox Code Playgroud)

内部get_options:

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

我的程序工作正常,但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)
Run Code Online (Sandbox Code Playgroud)

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

das*_*ght 38

strcpy添加一个null终止符'\0'.你忘了为它分配空间:

*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
Run Code Online (Sandbox Code Playgroud)

您需要为5个字符添加空格:4表示".tde"后缀,还有一个表示'\0'终结符.您当前的代码仅分配4,因此最后一次写入是在为新文件名分配的块之后立即完成的(即它后面的0个字节).

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

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

直接分配*filename会产生内存泄漏,因为*filename指向下面的指针会在失败时被覆盖,变得不可恢复.

  • @ Oz123假设该块从0x8000开始,长度为8个字节.然后块的最后一个有效地址是0x8007,而0x8008将是它之后的第一个无效地址.当valgrind在0x8008处看到写入时,它将其报告为对非法块的初始字节的写入,就像它是一个字节数组一样,并且它使用从零开始的表示法来报告偏移量. (8认同)
  • 好的,你已经看到了它.所以,`之后的'0字节'是Valgrind开发人员用简单的英语告诉我的方式:'它相邻',或"直接在它之后". (7认同)

Alg*_*man 6

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


Chr*_*Bao 5

分享我对这个问题的了解。

首先,错误消息具有误导性,尤其是“ ”一词after。一开始,我认为这意味着发生了一些事情after(在时间级别)我分配了一些内存块。但实际上,这意味着您正在从某个随机内存地址读取数据。该随机内存只是after(在地址空间中)您分配的内存块。

根据我的经验,通常当数组的索引超出范围时会发生这种情况。

我们看一下下面的简单演示代码:

#include <stdlib.h>
#include <stdio.h>

int main() {
    int *x = (int*)malloc(sizeof(int));
    x += 3; // x now points to invalid memory(some random location)
    printf("%d\n", *x); // read from an invalid location of memory
    *x = 4;             // write to an invalid location of memory
    free(x - 3);
    return EXIT_SUCCESS;

}
Run Code Online (Sandbox Code Playgroud)

valgrind运行备忘录检查时会产生以下错误消息

==4720== Invalid read of size 4
==4720==    at 0x1091AC: main (memo2.c:7)
==4720==  Address 0x4a5204c is 8 bytes after a block of size 4 alloc'd
==4720==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4720==    by 0x10919E: main (memo2.c:5)
==4720==
0
==4720== Invalid write of size 4
==4720==    at 0x1091C5: main (memo2.c:8)
==4720==  Address 0x4a5204c is 8 bytes after a block of size 4 alloc'd
==4720==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4720==    by 0x10919E: main (memo2.c:5)
Run Code Online (Sandbox Code Playgroud)