【问题标题】:How to avoid this valgrind warning on realloc?如何在 realloc 上避免这个 valgrind 警告?
【发布时间】:2016-03-14 02:28:59
【问题描述】:

我一直在为 realloc 与 valgrind 无法正常工作的一个奇怪案例争论不休。似乎我要么以某种方式分配太多,要么不正确地使用realloc。我非常重视 valgrind 错误,这样的错误让我非常担心。

最小的工作示例:

#include <stdlib.h>

typedef struct test {
    size_t n;
    size_t r;
    int **ptrs;
} test;

test *new_test() {
    test *t = malloc(sizeof(test));
    t->n = 0; //number of elements
    t->r = 1; //reserve
    t->ptrs = calloc(t->r, sizeof(*(t->ptrs))); //calloc inits so we don't have to
    return t;
}

void push_back_test(test *t, int *ptr) {
    if (t->n == t->r) {
        t->r <<= 1;
        int **temp_ptr = realloc(t->ptrs, sizeof(t->ptrs) * t->r);
        if (temp_ptr) {
            t->ptrs = temp_ptr;
        } else {
            exit(EXIT_FAILURE);
        }
        //NULL out the rest 
        for (int **ptri = t->ptrs + t->n; ptri < t->ptrs + t->r; ++ptri) {
            (*ptri) = NULL;
        }
    }
    t->ptrs[t->n] = ptr;
    ++(t->n);
}

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

    test *t = new_test();
    int *a = calloc(2, sizeof(int)); //calloc inits
    int *b = calloc(4, sizeof(int));
    int *c = calloc(8, sizeof(int));

    push_back_test(t, a);
    push_back_test(t, b);
    push_back_test(t, c);
    push_back_test(t, a);
    push_back_test(t, b);

    exit(EXIT_SUCCESS);
}

Valgrind 输出:

==26528== Memcheck, a memory error detector
==26528== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==26528== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==26528== Command: ./test
==26528== 
==26528== Conditional jump or move depends on uninitialised value(s)
==26528==    at 0x435A32: __linkin_atfork (in /----/----/test)
==26528==    by 0x414905: ptmalloc_init.part.8 (in /----/----/test)
==26528==    by 0x414C7F: malloc_hook_ini (in /----/----/test)
==26528==    by 0x465B1A: _dl_get_origin (in /----/----/test)
==26528==    by 0x436AB4: _dl_non_dynamic_init (in /----/----/test)
==26528==    by 0x437916: __libc_init_first (in /----/----/test)
==26528==    by 0x40140F: (below main) (in /----/----/test)
==26528== 
==26528== Conditional jump or move depends on uninitialised value(s)
==26528==    at 0x4104BA: _int_free (in /----/----/test)
==26528==    by 0x412C3B: _int_realloc (in /----/----/test)
==26528==    by 0x414046: realloc (in /----/----/test)
==26528==    by 0x40109D: push_back_test (test.c:20)
==26528==    by 0x4011FB: main (test.c:44)
==26528== 
==26528== Conditional jump or move depends on uninitialised value(s)
==26528==    at 0x410518: _int_free (in /----/----/test)
==26528==    by 0x412C3B: _int_realloc (in /----/----/test)
==26528==    by 0x414046: realloc (in /----/----/test)
==26528==    by 0x40109D: push_back_test (test.c:20)
==26528==    by 0x4011FB: main (test.c:44)
==26528== 
==26528== 
==26528== HEAP SUMMARY:
==26528==     in use at exit: 0 bytes in 0 blocks
==26528==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==26528== 
==26528== All heap blocks were freed -- no leaks are possible
==26528== 
==26528== For counts of detected and suppressed errors, rerun with: -v
==26528== Use --track-origins=yes to see where uninitialised values come from
==26528== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

现在我知道第一个错误可能是我的 libc 的问题,但其余的基本上是在告诉我,我并没有清空我分配的所有内存,而是在传递垃圾,我相信这不可能是我现在的样子取消新分配的内容。

我对此尝试了许多变体,它们要么(正确地)崩溃,要么给出这些消息。我很茫然。

编辑:我有问题的原始代码比这更正确。 我现在已经修好了 MWE,还是一样。

【问题讨论】:

  • test *new_test() 不返回指向 test * 类型的指针。
  • 开启编译器警告。
  • 我有原始代码。 MWE 错了,现在结果相同。
  • 觉得这有点难以置信 - 这些错误将是没有返回语句的直接结果。
  • gcc -std=gnu11 -Wall -static -g test.c -o test then valgrind ./test valgrind 输出与原始输出相同

标签: c valgrind


【解决方案1】:

问题是 glibc 不是 Valgrind-clean。通常,这些错误似乎来自您的libc.so.6,Valgrind 有内置的抑制功能。当您静态链接时,这些问题似乎源自您的二进制文件,因此不会被抑制。

您可以通过不静态链接或使用suppressionssuppression files 来解决此问题

如果您查看所抱怨的内容,那就是一些线程本地存储正在与 NULL 进行比较。如果你附加一个调试器,事实证明一切都初始化得很好,问题是误报。

更多信息请访问this SO thread

当然,多个 cmets 会使用 new_test 指出您的原始错误,并使用您传递给 realloc 的大小指出现有错误。修复这些问题后,Valgrind 警告仍然存在,这就是原因。

【讨论】:

  • 谢谢,是的,问题是静态的。 new_test 的错误不存在于原始代码中,这就是为什么我首先开始这个问题,但是大小错误,虽然最终不是我平台上的sizeof(void **)==sizeof(void *) 的结果错误(我假设大多数主流的也是如此,)是一个可能会导致问题的问题,但同样对 valgrind 没有任何改变。
【解决方案2】:

您似乎以不正确的大小调用realloc

realloc(t->ptrs, sizeof(t->ptrs) * t->r);

应该改为:

realloc(t->ptrs, sizeof(*t->ptrs) * t->r);

由于t-&gt;ptrs 被定义为int **ptrs;,因此计算在您和大多数现代平台上给出相同的结果。因此,正如 dho 正确评论的那样,此错误没有任何后果,也不能解释问题。

【讨论】:

  • 这是对的,但解决这个问题并不能解决 Valgrind 中的问题。
  • 这不是导致问题的原因,但也是一个有效的观点,谢谢。
猜你喜欢
  • 1970-01-01
  • 2016-12-25
  • 2021-02-04
  • 1970-01-01
  • 2019-02-21
  • 1970-01-01
  • 2021-11-08
  • 1970-01-01
  • 2021-09-01
相关资源
最近更新 更多