Describe the bug
The unit test tests/test-path-manager
leaks memory, and contains memory violations despite a successful run.
To Reproduce
Steps to reproduce the behavior:
./configure --enable-debug
make check
./libtool --mode=execute valgrind --leak-check=full tests/test-path-manager
Expected behavior
No leaks should be detected at test-path-manager
process exit. The Valgrind summary should look similar to the following, in particular "no leaks possible
":
==26069== HEAP SUMMARY:
==26069== in use at exit: 0 bytes in 0 blocks
==26069== total heap usage: 37 allocs, 37 frees, 30,696 bytes allocated
==26069==
==26069== All heap blocks were freed -- no leaks are possible
==26069==
==26069== For counts of detected and suppressed errors, rerun with: -v
==26069== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Screenshots
==25640== Memcheck, a memory error detector
==25640== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==25640== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==25640== Command: /home/void/MPTCP/OTC/mptcpd/genl-update/tests/.libs/test-path-manager
==25640==
configuration.c:check_file_perms() File "/usr/local/etc/mptcpd/mptcpd.conf" does not exist.
configuration.c:parse_config_file() Unable to mptcpd load settings from file '/usr/local/etc/mptcpd/mptcpd.conf'
configuration.c:mptcpd_config_create() plugin directory: /home/void/MPTCP/OTC/mptcpd/genl-update/tests/plugins_noop
TEST: pm_create
TEST: pm_destroy
==25640== Invalid read of size 8
==25640== at 0x485D11B: l_queue_push_tail (queue.c:141)
==25640== by 0x4863F15: l_netlink_send (netlink.c:438)
==25640== by 0x484939B: send_getaddr_command (network_monitor.c:845)
==25640== by 0x4863792: destroy_command (netlink.c:76)
==25640== by 0x485D9DB: l_hashmap_destroy (hashmap.c:336)
==25640== by 0x4863DC9: l_netlink_destroy (netlink.c:379)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== Address 0x4ac6948 is 8 bytes inside a block of size 24 free'd
==25640== at 0x483997B: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x4863DAE: l_netlink_destroy (netlink.c:377)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== by 0x485D4D7: l_queue_foreach (queue.c:441)
==25640== by 0x4860B0C: l_main_iterate (main.c:486)
==25640== by 0x4860B8B: l_main_run (main.c:520)
==25640== by 0x10A5C6: main (test-path-manager.c:127)
==25640== Block was alloc'd at
==25640== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x485B76D: l_malloc (util.c:62)
==25640== by 0x485D04D: l_queue_new (queue.c:63)
==25640== by 0x4863D1D: l_netlink_new (netlink.c:359)
==25640== by 0x484A008: mptcpd_nm_create (network_monitor.c:873)
==25640== by 0x10BE04: mptcpd_pm_create (path_manager.c:748)
==25640== by 0x10A3E0: test_pm_create (test-path-manager.c:38)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== by 0x485D4D7: l_queue_foreach (queue.c:441)
==25640== by 0x4860B0C: l_main_iterate (main.c:486)
==25640==
==25640== Invalid read of size 8
==25640== at 0x485D133: l_queue_push_tail (queue.c:146)
==25640== by 0x4863F15: l_netlink_send (netlink.c:438)
==25640== by 0x484939B: send_getaddr_command (network_monitor.c:845)
==25640== by 0x4863792: destroy_command (netlink.c:76)
==25640== by 0x485D9DB: l_hashmap_destroy (hashmap.c:336)
==25640== by 0x4863DC9: l_netlink_destroy (netlink.c:379)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== Address 0x4ac6940 is 0 bytes inside a block of size 24 free'd
==25640== at 0x483997B: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x4863DAE: l_netlink_destroy (netlink.c:377)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== by 0x485D4D7: l_queue_foreach (queue.c:441)
==25640== by 0x4860B0C: l_main_iterate (main.c:486)
==25640== by 0x4860B8B: l_main_run (main.c:520)
==25640== by 0x10A5C6: main (test-path-manager.c:127)
==25640== Block was alloc'd at
==25640== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x485B76D: l_malloc (util.c:62)
==25640== by 0x485D04D: l_queue_new (queue.c:63)
==25640== by 0x4863D1D: l_netlink_new (netlink.c:359)
==25640== by 0x484A008: mptcpd_nm_create (network_monitor.c:873)
==25640== by 0x10BE04: mptcpd_pm_create (path_manager.c:748)
==25640== by 0x10A3E0: test_pm_create (test-path-manager.c:38)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== by 0x485D4D7: l_queue_foreach (queue.c:441)
==25640== by 0x4860B0C: l_main_iterate (main.c:486)
==25640==
==25640== Invalid write of size 8
==25640== at 0x485D137: l_queue_push_tail (queue.c:144)
==25640== by 0x4863F15: l_netlink_send (netlink.c:438)
==25640== by 0x484939B: send_getaddr_command (network_monitor.c:845)
==25640== by 0x4863792: destroy_command (netlink.c:76)
==25640== by 0x485D9DB: l_hashmap_destroy (hashmap.c:336)
==25640== by 0x4863DC9: l_netlink_destroy (netlink.c:379)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== Address 0x4ac6948 is 8 bytes inside a block of size 24 free'd
==25640== at 0x483997B: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x4863DAE: l_netlink_destroy (netlink.c:377)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== by 0x485D4D7: l_queue_foreach (queue.c:441)
==25640== by 0x4860B0C: l_main_iterate (main.c:486)
==25640== by 0x4860B8B: l_main_run (main.c:520)
==25640== by 0x10A5C6: main (test-path-manager.c:127)
==25640== Block was alloc'd at
==25640== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x485B76D: l_malloc (util.c:62)
==25640== by 0x485D04D: l_queue_new (queue.c:63)
==25640== by 0x4863D1D: l_netlink_new (netlink.c:359)
==25640== by 0x484A008: mptcpd_nm_create (network_monitor.c:873)
==25640== by 0x10BE04: mptcpd_pm_create (path_manager.c:748)
==25640== by 0x10A3E0: test_pm_create (test-path-manager.c:38)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== by 0x485D4D7: l_queue_foreach (queue.c:441)
==25640== by 0x4860B0C: l_main_iterate (main.c:486)
==25640==
==25640== Invalid write of size 8
==25640== at 0x485D150: l_queue_push_tail (queue.c:147)
==25640== by 0x4863F15: l_netlink_send (netlink.c:438)
==25640== by 0x484939B: send_getaddr_command (network_monitor.c:845)
==25640== by 0x4863792: destroy_command (netlink.c:76)
==25640== by 0x485D9DB: l_hashmap_destroy (hashmap.c:336)
==25640== by 0x4863DC9: l_netlink_destroy (netlink.c:379)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== Address 0x4ac6940 is 0 bytes inside a block of size 24 free'd
==25640== at 0x483997B: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x4863DAE: l_netlink_destroy (netlink.c:377)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== by 0x485D4D7: l_queue_foreach (queue.c:441)
==25640== by 0x4860B0C: l_main_iterate (main.c:486)
==25640== by 0x4860B8B: l_main_run (main.c:520)
==25640== by 0x10A5C6: main (test-path-manager.c:127)
==25640== Block was alloc'd at
==25640== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x485B76D: l_malloc (util.c:62)
==25640== by 0x485D04D: l_queue_new (queue.c:63)
==25640== by 0x4863D1D: l_netlink_new (netlink.c:359)
==25640== by 0x484A008: mptcpd_nm_create (network_monitor.c:873)
==25640== by 0x10BE04: mptcpd_pm_create (path_manager.c:748)
==25640== by 0x10A3E0: test_pm_create (test-path-manager.c:38)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== by 0x485D4D7: l_queue_foreach (queue.c:441)
==25640== by 0x4860B0C: l_main_iterate (main.c:486)
==25640==
==25640== Invalid read of size 4
==25640== at 0x485D158: l_queue_push_tail (queue.c:149)
==25640== by 0x4863F15: l_netlink_send (netlink.c:438)
==25640== by 0x484939B: send_getaddr_command (network_monitor.c:845)
==25640== by 0x4863792: destroy_command (netlink.c:76)
==25640== by 0x485D9DB: l_hashmap_destroy (hashmap.c:336)
==25640== by 0x4863DC9: l_netlink_destroy (netlink.c:379)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== Address 0x4ac6950 is 16 bytes inside a block of size 24 free'd
==25640== at 0x483997B: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x4863DAE: l_netlink_destroy (netlink.c:377)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== by 0x485D4D7: l_queue_foreach (queue.c:441)
==25640== by 0x4860B0C: l_main_iterate (main.c:486)
==25640== by 0x4860B8B: l_main_run (main.c:520)
==25640== by 0x10A5C6: main (test-path-manager.c:127)
==25640== Block was alloc'd at
==25640== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x485B76D: l_malloc (util.c:62)
==25640== by 0x485D04D: l_queue_new (queue.c:63)
==25640== by 0x4863D1D: l_netlink_new (netlink.c:359)
==25640== by 0x484A008: mptcpd_nm_create (network_monitor.c:873)
==25640== by 0x10BE04: mptcpd_pm_create (path_manager.c:748)
==25640== by 0x10A3E0: test_pm_create (test-path-manager.c:38)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640== by 0x10A4E7: idle_callback (test-path-manager.c:86)
==25640== by 0x4860305: idle_dispatch (main.c:333)
==25640== by 0x485D4D7: l_queue_foreach (queue.c:441)
==25640== by 0x4860B0C: l_main_iterate (main.c:486)
==25640==
==25640==
==25640== HEAP SUMMARY:
==25640== in use at exit: 16 bytes in 1 blocks
==25640== total heap usage: 77 allocs, 76 frees, 76,319 bytes allocated
==25640==
==25640== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
==25640== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==25640== by 0x485B76D: l_malloc (util.c:62)
==25640== by 0x485D11A: l_queue_push_tail (queue.c:136)
==25640== by 0x4863F15: l_netlink_send (netlink.c:438)
==25640== by 0x484939B: send_getaddr_command (network_monitor.c:845)
==25640== by 0x4863792: destroy_command (netlink.c:76)
==25640== by 0x485D9DB: l_hashmap_destroy (hashmap.c:336)
==25640== by 0x4863DC9: l_netlink_destroy (netlink.c:379)
==25640== by 0x4849F0B: mptcpd_nm_destroy (network_monitor.c:972)
==25640== by 0x10BD17: mptcpd_pm_destroy (path_manager.c:764)
==25640== by 0x10A4AE: test_pm_destroy (test-path-manager.c:51)
==25640== by 0x485C238: l_test_run (test.c:83)
==25640==
==25640== LEAK SUMMARY:
==25640== definitely lost: 16 bytes in 1 blocks
==25640== indirectly lost: 0 bytes in 0 blocks
==25640== possibly lost: 0 bytes in 0 blocks
==25640== still reachable: 0 bytes in 0 blocks
==25640== suppressed: 0 bytes in 0 blocks
==25640==
==25640== For counts of detected and suppressed errors, rerun with: -v
==25640== ERROR SUMMARY: 7 errors from 6 contexts (suppressed: 0 from 0)
Desktop (please complete the following information):
- Linux Kernel: 5.0.0
- Compiler: gcc 8.3
Additional context
The call stack shows the static
function send_getaddr_command()
being called as the Netlink destroy command. That really shouldn't happen, but occurs because of a workaround in the mptcpd network monitor for an issue in the ELL l_netlink
API that allows the second call to l_netlink_send()
to be processed asynchronously prior to completion of the first l_netlink_send()
. The code in question is in lib/network_monitor.c:
/**
* Get network interface information.
*
* @note We force the second rtnetlink command, RTM_GETADDR,
* to be sent after this one completes by doing so in
* the destroy callback for this command. That
* guarantees that the potential multipart message
* response from this dump is fully read prior to
* sending the second command. This works around an
* issue in ELL where it was possible that the second
* command would be sent prior to receiving all of the
* parts of the multipart @c RTM_GETLINK response, which
* resulted in an EBUSY error.
*/
struct ifinfomsg link_msg = { .ifi_family = AF_UNSPEC };
if (l_netlink_send(nm->rtnl,
RTM_GETLINK,
NLM_F_DUMP,
&link_msg,
sizeof(link_msg),
handle_rtm_getlink,
nm,
send_getaddr_command)
== 0) {
l_error("Unable to obtain network devices.");
mptcpd_nm_destroy(nm);
return NULL;
}
The send_getaddr_command()
function gets called as the "destroy command" even though that is not what we really want in the case of the tests/test-path-manager
unit test. The test/test-network-monitor
unit test doesn't exhibit a memory leak, so we should look into what is done differently in tests/test-path-manager
that ultimately triggers the leak.