valgrind在asprintf调用后检测内存泄漏,即使在调用free

时间:2017-01-17 00:27:53

标签: c memory-leaks valgrind

我的代码如下所示:

bool
amflinkd_apteryx_set_action (const char *address, char *action)
{
    bool ret = false;
    char *path = NULL;

    if (asprintf (&path, "%s/%s", AMFLINKD_IP_ADDRESS_PATH, address) > 0)
    {
        ret = apteryx_set_string (path, "action", action);
    }

    free (path);
    return ret;
}

然后我对它执行单元测试,在其上执行valgrind。我的输出是:

np: running: "amflinkd_apteryx_unit_tests.amflinkd_apteryx_set_action_true"
EVENT SLMATCH err: SET: Not initialised
at 0x805B512: np::spiegel::describe_stacktrace (np/spiegel/spiegel.cxx)
by 0x804BAD3: np::event_t::with_stack (np/event.cxx)
by 0x8067688: np::mock_syslog (isyslog.c)
by 0x8079EA8: np::spiegel::platform::intercept_tramp (np/spiegel/platform/linux_x86.cxx)
by 0x412BC71:

==4== 33 bytes in 1 blocks are definitely lost in loss record 323 of 525
==4==    at 0x402B19B: malloc (vg_replace_malloc.c:299)
==4==    by 0x47ECAA7: vasprintf (vasprintf.c:73)
==4==    by 0x47CFEEA: asprintf (asprintf.c:35)
==4==    by 0x804B392: amflinkd_apteryx_set_action (amflinkd_apteryx.c:33)
==4==    by 0x804B28F: test_amflinkd_apteryx_set_action_true (amflinkd_apteryx_unit_tests.c:38)
==4==    by 0x805B0F1: np::spiegel::function_t::invoke(std::vector<np::spiegel::value_t, std::allocator<np::spiegel::value_t> >) const (spiegel.cxx:606)
==4==    by 0x804F68A: np::runner_t::run_function(np::functype_t, np::spiegel::function_t*) (runner.cxx:526)
==4==    by 0x804FEF6: np::runner_t::run_test_code(np::job_t*) (runner.cxx:650)
==4==    by 0x805019D: np::runner_t::begin_job(np::job_t*) (runner.cxx:710)
==4==    by 0x804E694: np::runner_t::run_tests(np::plan_t*) (runner.cxx:147)
==4==    by 0x8050374: np_run_tests (runner.cxx:822)
==4==    by 0x804BA7D: main (main.c:108)
==4== 
{
   <insert_a_suppression_name_here>
   Memcheck:Leak
   match-leak-kinds: definite
   fun:malloc
   fun:vasprintf
   fun:asprintf
   fun:amflinkd_apteryx_set_action
   fun:test_amflinkd_apteryx_set_action_true
   fun:_ZNK2np7spiegel10function_t6invokeESt6vectorINS0_7value_tESaIS3_EE
   fun:_ZN2np8runner_t12run_functionENS_10functype_tEPNS_7spiegel10function_tE
   fun:_ZN2np8runner_t13run_test_codeEPNS_5job_tE
   fun:_ZN2np8runner_t9begin_jobEPNS_5job_tE
   fun:_ZN2np8runner_t9run_testsEPNS_6plan_tE
   fun:np_run_tests
   fun:main
}
==4== 40 bytes in 1 blocks are definitely lost in loss record 335 of 525
==4==    at 0x402B19B: malloc (vg_replace_malloc.c:299)
==4==    by 0x47ECAA7: vasprintf (vasprintf.c:73)
==4==    by 0x47CFEEA: asprintf (asprintf.c:35)
==4==    by 0x412D10B: apteryx_cas_string (apteryx.c:530)
==4==    by 0x412D1BC: apteryx_set_string (apteryx.c:544)
==4==    by 0x804B3B0: amflinkd_apteryx_set_action (amflinkd_apteryx.c:35)
==4==    by 0x804B28F: test_amflinkd_apteryx_set_action_true (amflinkd_apteryx_unit_tests.c:38)
==4==    by 0x805B0F1: np::spiegel::function_t::invoke(std::vector<np::spiegel::value_t, std::allocator<np::spiegel::value_t> >) const (spiegel.cxx:606)
==4==    by 0x804F68A: np::runner_t::run_function(np::functype_t, np::spiegel::function_t*) (runner.cxx:526)
==4==    by 0x804FEF6: np::runner_t::run_test_code(np::job_t*) (runner.cxx:650)
==4==    by 0x805019D: np::runner_t::begin_job(np::job_t*) (runner.cxx:710)
==4==    by 0x804E694: np::runner_t::run_tests(np::plan_t*) (runner.cxx:147)
==4== 
{
   <insert_a_suppression_name_here>
   Memcheck:Leak
   match-leak-kinds: definite
   fun:malloc
   fun:vasprintf
   fun:asprintf
   fun:apteryx_cas_string
   fun:apteryx_set_string
   fun:amflinkd_apteryx_set_action
   fun:test_amflinkd_apteryx_set_action_true
   fun:_ZNK2np7spiegel10function_t6invokeESt6vectorINS0_7value_tESaIS3_EE
   fun:_ZN2np8runner_t12run_functionENS_10functype_tEPNS_7spiegel10function_tE
   fun:_ZN2np8runner_t13run_test_codeEPNS_5job_tE
   fun:_ZN2np8runner_t9begin_jobEPNS_5job_tE
   fun:_ZN2np8runner_t9run_testsEPNS_6plan_tE
}
EVENT VALGRIND 73 bytes of memory leaked


EVENT VALGRIND 2 unsuppressed errors found by valgrind


FAIL amflinkd_apteryx_unit_tests.amflinkd_apteryx_set_action_true

第一次泄漏应该是&#34;路径&#34;指针,但我在返回之前释放它。 我不知道第二次泄漏是什么。

这是调用amflinkd_apteryx_set_action()函数的单元测试函数:

void
test_amflinkd_apteryx_set_action_true (void)
{
    printf("Running test_amflinkd_apteryx_set_action_true test.");
    const char *address = {"192.168.1.5"};
    char *action = {"drop"};
    bool res = amflinkd_apteryx_set_action (address, action);
    NP_ASSERT_TRUE (res);
}

以下是apteryx_set_string()

的代码
bool
apteryx_cas_string (const char *path, const char *key, const char *value, uint64_t ts)
{
    char *full_path;
    size_t len;
    bool res = false;

    /* Create full path */
    if (key)
        len = asprintf (&full_path, "%s/%s", path, key);
    else
        len = asprintf (&full_path, "%s", path);
    if (len)
    {
        res = apteryx_cas (full_path, value, ts);
        free (full_path);
    }
    return res;
}

bool
apteryx_set_string (const char *path, const char *key, const char *value)
{
    return apteryx_cas_string (path, key, value, UINT64_MAX);
}

我重试了我的amflinkd_apteryx_set_action():

bool
amflinkd_apteryx_set_action (const char *address, char *action)
{
    bool ret = false;
    char *path = NULL;

    if (asprintf (&path, "%s/%s", AMFLINKD_IP_ADDRESS_PATH, address) > 0)
    {
        ret = true; //apteryx_set_string (path, "action", action);
    }

    free (path);
    return ret;
}

这没有内存泄漏。 然后我试了一下:

bool
amflinkd_apteryx_set_action (const char *address, char *action)
{
    bool ret = false;
    char *path = NULL;

    if (asprintf (&path, "%s/%s", AMFLINKD_IP_ADDRESS_PATH, address) > 0)
    {
        ret = apteryx_test_string (path, "action", action);
    }

    free (path);
    return ret;
}

bool
apteryx_test_string (const char *path, const char *key, const char *value)
{
    char *full_path;
    size_t len;
    bool res = false;

    /* Create full path */
    if (key)
        len = asprintf (&full_path, "%s/%s", path, key);
    else
        len = asprintf (&full_path, "%s", path);
    if (len)
    {
        res = true;
        free (full_path);
    }
    return res;
}

这也没有内存泄漏。它必须是apteryx_set_string()中的一个东西,它可以防止释放内存或丢失引用。

我明白了! 代码正在点击ASSERT

ASSERT ((ref_count > 0), return false, "SET: Not initialised\n");

apteryx_set_string()函数中有两个更深的调用。由于断言,free没有被调用,valgrind选择了内存泄漏。 谢谢你的帮助。

2 个答案:

答案 0 :(得分:1)

我明白了! 代码正在点击ASSERT

ASSERT ((ref_count > 0), return false, "SET: Not initialised\n");

apteryx_set_string()函数中有两个更深的调用。由于断言,free没有被调用,valgrind选择了内存泄漏。 谢谢你的帮助。

答案 1 :(得分:-1)

这可能是一个范围问题。尝试在if块中释放。

在if语句中创建的变量,对于我的回忆,只存在于if块中。因此,你已经通过if块的右括号丢失了它。

当您在块之外声明变量时,在if语句期间调用asprintf()之前不会发生分配。

修改 为了提供更多信息,我的想法是asprintf是声明实际变量的那个,它给出的指针只是指向它。如果是这种情况,那么丢失的变量声明在if语句

第二次修改 我测试了以下内容并且无法重现:

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

void test() {
  char *str = NULL;

  if (asprintf(&str, "%s", "foo") > 0) {
    printf("%s\n", str);
  }

  free(str);
}

int main() {
  test();
  return 0;
}

GCC命令行:

gcc -g -D_GNU_SOURCE -I/usr/include asprintf.c

输出:

valgrind ./a.out
==2461== Memcheck, a memory error detector
==2461== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==2461== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==2461== Command: ./a.out
==2461==
foo
==2461==
==2461== HEAP SUMMARY:
==2461==     in use at exit: 0 bytes in 0 blocks
==2461==   total heap usage: 3 allocs, 3 frees, 1,128 bytes allocated
==2461==
==2461== All heap blocks were freed -- no leaks are possible
==2461==
==2461== For counts of detected and suppressed errors, rerun with: -v
==2461== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)