Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Valgrind report 'still reachable' warning on test_name #57

Open
perror opened this issue May 28, 2019 · 2 comments
Open

Valgrind report 'still reachable' warning on test_name #57

perror opened this issue May 28, 2019 · 2 comments

Comments

@perror
Copy link

perror commented May 28, 2019

I have strange behavior with valgrind. Basically, I defined my test suite as follow:

  /* Set the test cases */
  MunitTest test_cases[] =
    {
     { "trace/instr", test_instr, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
     { "trace/hash", test_hash, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
     { "trace/hashtable", test_hashtable, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
     { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
    };

  /* Set the test suite */
  const MunitSuite test_suite[] =
    {
     { "libafl/", test_cases, NULL, 1, MUNIT_SUITE_OPTION_NONE },
     { NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE }
    };

But, the problem is that valgrind detect a "still reachable" memory area in each process. For example the last test gives:

[ OK    ] [ 0.00903018 / 0.00862850 CPU ]
libafl/trace/hashtable               ==8031== 
==8031== HEAP SUMMARY:
==8031==     in use at exit: 23 bytes in 1 blocks
==8031==   total heap usage: 21 allocs, 20 frees, 5,050 bytes allocated
==8031== 
==8031== 23 bytes in 1 blocks are still reachable in loss record 1 of 1
==8031==    at 0x483577F: malloc (vg_replace_malloc.c:299)
==8031==    by 0x4848C03: munit_maybe_concat (munit.c:1110)
==8031==    by 0x484A7D8: munit_test_runner_run_test (munit.c:1556)
==8031==    by 0x484B028: munit_test_runner_run_suite (munit.c:1677)
==8031==    by 0x484B1A0: munit_test_runner_run (munit.c:1696)
==8031==    by 0x484CAA5: munit_suite_main_custom (munit.c:2026)
==8031==    by 0x484CCCA: munit_suite_main (munit.c:2054)
==8031==    by 0x10BD45: main (test_trace.c:189)
==8031== 
==8031== LEAK SUMMARY:
==8031==    definitely lost: 0 bytes in 0 blocks
==8031==    indirectly lost: 0 bytes in 0 blocks
==8031==      possibly lost: 0 bytes in 0 blocks
==8031==    still reachable: 23 bytes in 1 blocks
==8031==         suppressed: 0 bytes in 0 blocks
==8031== 
==8031== For counts of detected and suppressed errors, rerun with: -v
==8031== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
[ OK    ] [ 0.01238986 / 0.01177837 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped.
==8028== 
==8028== HEAP SUMMARY:
==8028==     in use at exit: 0 bytes in 0 blocks
==8028==   total heap usage: 12 allocs, 12 frees, 4,612 bytes allocated
==8028== 
==8028== All heap blocks were freed -- no leaks are possible
==8028== 
==8028== For counts of detected and suppressed errors, rerun with: -v
==8028== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Note that the size of the "still reachable" memory area is exactly the size of the string enclosing the name of the test (plus the \0 character at the end).

One way to make the error vanish seems to simply declare the test suite as follow:

 /* Set the test cases */
  MunitTest test_cases[] =
    {
     { "libafl/trace/instr", test_instr, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
     { "libafl/trace/hash", test_hash, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
     { "libafl/trace/hashtable", test_hashtable, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
     { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
    };

  /* Set the test suite */
  const MunitSuite test_suite[] =
    {
     { "", test_cases, NULL, 1, MUNIT_SUITE_OPTION_NONE },
     { NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE }
    };

The root name of the test suite is empty and this time valgrind gives a clean report for each test:

All heap blocks were freed -- no leaks are possible

I tried to see what was the problem but couldn't find a good way to solve it (everything seems to be linked to the munit_maybe_free_concat(() function).

@dargueta
Copy link

I pulled master and the leak is still happening.

@yetsing
Copy link

yetsing commented May 30, 2024

This is because it uses the fork subprocess to perform testing, and after the subprocess completes the testing, it stops directly. ==8031== part is the child process of fork, while the ==8028== part is the main process.

The following is a code example to demonstrate the reason

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

void
hello() {
    int pid = fork();
    assert(pid >= 0);
    if (pid == 0) {
        // child process
        exit(0);
    }
    waitpid(pid, NULL, 0);
}

int
main() {
    char *s = malloc(32);
    printf("hello world\n");
    hello();
    free(s);
    return 0;
}

save code to hello.c.

gcc hello.c
valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./a.out

You will see similar output below

==239150== Memcheck, a memory error detector
==239150== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==239150== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==239150== Command: ./a.out
==239150==
hello world
==239151==
==239151== HEAP SUMMARY:
==239151==     in use at exit: 32 bytes in 1 blocks
==239151==   total heap usage: 2 allocs, 1 frees, 1,056 bytes allocated
==239151==
==239151== 32 bytes in 1 blocks are still reachable in loss record 1 of 1
==239151==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==239151==    by 0x109287: main (in /home/ecs-user/cbdai/a.out)
==239151==
==239151== LEAK SUMMARY:
==239151==    definitely lost: 0 bytes in 0 blocks
==239151==    indirectly lost: 0 bytes in 0 blocks
==239151==      possibly lost: 0 bytes in 0 blocks
==239151==    still reachable: 32 bytes in 1 blocks
==239151==         suppressed: 0 bytes in 0 blocks
==239151==
==239151== For lists of detected and suppressed errors, rerun with: -s
==239151== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==239150==
==239150== HEAP SUMMARY:
==239150==     in use at exit: 0 bytes in 0 blocks
==239150==   total heap usage: 2 allocs, 2 frees, 1,056 bytes allocated
==239150==
==239150== All heap blocks were freed -- no leaks are possible
==239150==
==239150== For lists of detected and suppressed errors, rerun with: -s
==239150== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants