Valgrind无效读取错误,即使没有内存泄漏

时间:2016-03-14 04:58:00

标签: c memory memory-leaks valgrind

所以我在" main.c"

中有这样的东西
#include "foo.h"
#include <stdio.h>
#include <stdlib.h>

typedef struct myStruct
{
    int dummyMember1;
    float dummyMember2;
} myStruct_t;

int main()
{
    myStruct_t* a = malloc(sizeof(myStruct_t));
    a->dummyMember1 = 10;
    a->dummyMember2 = 5.5;
    push(a);

    myStruct_t* b = pop();
    if(b != NULL)
    {
        b->dummyMember1;
        b->dummyMember2;
    }

    free(b);
    return 0;
}

然后我在某个文件&#34; foo.h&#34;

中有类似的东西
void push(void* item);
void* pop();

在&#34; foo.c&#34;我有类似的东西

#include "foo.h"
#include <stdlib.h>
#include <string.h>

#define ARR_SIZE 50

void* arr[ARR_SIZE];

int free_space = ARR_SIZE;

void push(void* item)
{
    if(free_space > 0){
        arr[ARR_SIZE - free_space] = item;
        free_space--;
    }
    return;
}

void* pop()
{
    void* p_ret = NULL;
    if(free_space < ARR_SIZE)
    {
        void* p = arr[ARR_SIZE-(free_space+1)];
        p_ret = malloc(sizeof(*p));
        memcpy(p_ret, p, sizeof(*p));
        free(p);
        free_space++;
    }
    return p_ret;
}

此代码编译并在没有段错误的情况下运行,但问题是valgrind报告了无效的读取错误(即使它说&#34;所有堆块都被释放 - 没有泄漏可能&#34;)。

我的问题是,是什么导致valgrind报告无效的读错误(这都是指pop()函数)?

2 个答案:

答案 0 :(得分:0)

只关心编译而不是结果。两个地方可能是错的。 第一个:

myStruct_t* structVar = pop();
//it can not realize structVar like this,you must use 'force converse'.
myStruct_t* structVar = (myStruct_t *)pop();

第二个:

p_ret = malloc(sizeof(*p));
//sizeof() parameters must be Object ,data type,and size.
p_ret = malloc(sizeof(p));
memcpy(p_ret, p, sizeof(p));

希望对你有所帮助。

答案 1 :(得分:0)

push()pop()中的代码有点令人费解。在我的首选编译器选项下编译代码并进行最少的必要更改,然后在valgrind下运行它,我收到警告:

==59504== Invalid read of size 4
==59504==    at 0x100000EBF: main (main.c:21)
==59504==  Address 0x100aa74e4 is 3 bytes after a block of size 1 alloc'd
==59504==    at 0x100007E81: malloc (vg_replace_malloc.c:302)
==59504==    by 0x100000E50: pop (foo.c:26)
==59504==    by 0x100000EA4: main (main.c:18)

麻烦在于你的pop()功能;您正尝试在sizeof(*p)p的位置分配void *字节,因此*pvoid,其大小不足。 GCC(在我看来无用)将其视为对1字节的请求,而不是给出应该给出的错误。您必须请求-pedantic警告才能收到消息:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -Werror -pedantic -c foo.c
foo.c: In function ‘pop’:
foo.c:26:30: error: invalid application of ‘sizeof’ to a void type [-Werror=pointer-arith]
         p_ret = malloc(sizeof(*p));
                              ^
In file included from /usr/include/string.h:186:0,
                 from foo.c:3:
foo.c:27:32: error: invalid application of ‘sizeof’ to a void type [-Werror=pointer-arith]
         memcpy(p_ret, p, sizeof(*p));
cc1: all warnings being treated as errors
$

由于您将void *值存储在固定数组中,因此堆栈中不需要任何动态内存分配。你可以使用:

#include "foo.h"

enum { ARR_SIZE = 50 };

static void *arr[ARR_SIZE];
static int   free_space = ARR_SIZE;

void push(void *item)
{
    if (free_space > 0)
    {
        arr[ARR_SIZE - free_space] = item;
        free_space--;
    }
}

void *pop(void)
{
    void *p_ret = 0;
    if (free_space < ARR_SIZE)
    {
        p_ret = arr[ARR_SIZE - (free_space + 1)];
        free_space++;
    }
    return p_ret;
}

修改后的测试程序:

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

typedef struct myStruct
{
    int dummyMember1;
    float dummyMember2;
} myStruct_t;

int main(void)
{
    for (int i = 0; i < 3; i++)
    {
        myStruct_t *a = malloc(sizeof(myStruct_t));
        a->dummyMember1 = 10 + i;
        a->dummyMember2 = 5.5 * i;
        push(a);

        myStruct_t *b = pop();
        if (b != NULL)
        {
            printf("Popped: %d and %f\n", b->dummyMember1, b->dummyMember2);
        }

        free(a);
    }
    return 0;
}

我得到valgrind输出,例如:

==59611== Memcheck, a memory error detector
==59611== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==59611== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==59611== Command: foo
==59611== 
--59611-- run: /usr/bin/dsymutil "./foo"
Popped: 10 and 0.000000
Popped: 11 and 5.500000
Popped: 12 and 11.000000
==59611== 
==59611== HEAP SUMMARY:
==59611==     in use at exit: 26,437 bytes in 189 blocks
==59611==   total heap usage: 274 allocs, 85 frees, 32,661 bytes allocated
==59611== 
==59611== LEAK SUMMARY:
==59611==    definitely lost: 80 bytes in 1 blocks
==59611==    indirectly lost: 68 bytes in 2 blocks
==59611==      possibly lost: 0 bytes in 0 blocks
==59611==    still reachable: 0 bytes in 0 blocks
==59611==         suppressed: 26,289 bytes in 186 blocks
==59611== Rerun with --leak-check=full to see details of leaked memory
==59611== 
==59611== For counts of detected and suppressed errors, rerun with: -v
==59611== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

那看起来很糟糕 - 失去了记忆。但是使用--leak-check=full运行会产生:

==59641== 148 (80 direct, 68 indirect) bytes in 1 blocks are definitely lost in loss record 43 of 66
==59641==    at 0x100007E81: malloc (vg_replace_malloc.c:302)
==59641==    by 0x1001E58D6: __Balloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==59641==    by 0x1001E2553: __rv_alloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==59641==    by 0x1001E2574: __nrv_alloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==59641==    by 0x10020B3E6: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==59641==    by 0x1002346C8: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==59641==    by 0x10020A389: vfprintf_l (in /usr/lib/system/libsystem_c.dylib)
==59641==    by 0x100208223: printf (in /usr/lib/system/libsystem_c.dylib)
==59641==    by 0x100000EA4: main (main.c:23)

我尝试添加fclose(stdout),但这并没有解决它。这个问题深埋在本地printf()函数内部,完全在你的控制范围内和我的控制之外。我需要添加抑制。 Mac OS X往往会有很多这类泄漏 - 见证已经原位的抑制(180+分配中几乎27 KiB)。

如果你真的必须在你的堆栈中使用内存分配,你需要仔细考虑你正在推动堆栈的内容,以及你正在弹出它的内容。您可能需要知道要存储的对象的大小。然后,您将通过修改压入堆栈的值来证明堆栈不受影响,因为堆栈复制了该值。当你只是堆叠指针时,如果当前数组太小时堆栈增长,你只需要动态内存分配。