Table of Contents
Piotr Jaroszyński: Usermode debugging under Linux
Week 8 [ Jul 12 - Jul 18 2010 ]
valgrind
I wasn't supposed to work on valgrind related stuff, but the following report keeps nagging me:
==31509== 360 bytes in 1 blocks are still reachable in loss record 4 of 5 ==31509== at 0x402C2E: realloc (malloc.c:316) ==31509== by 0x402DCE: malloc (malloc.c:351) ==31509== by 0x402DDC: zalloc (malloc.c:382) ==31509== by 0x404FF8: alloc_netdev (netdevice.c:329) ==31509== by 0x404185: alloc_etherdev (ethernet.c:186) ==31509== by 0x400041: tap_probe (tap.c:142) ==31509== by 0x40FE34: linux_probe (linux.c:42) ==31509== by 0x4020A8: probe_devices (device.c:47) ==31509== by 0x40BB42: startup (init.c:67) ==31509== by 0x40229E: main (main.c:48)
See, tap_probe()
is part of the tap driver that I wrote so that makes me look bad ;)
I have the issue half-fixed, but while debugging it I stumbled upon another bug, namely false reports like:
==31633== Invalid read of size 8 ==31633== at 0x4042CD: ipv4_create_routes (ipv4.c:593) ==31633== by 0x40124F: apply_settings (settings.c:374) ==31633== by 0x401869: register_settings (settings.c:451) ==31633== by 0x40FE8C: smbios_init (smbios_settings.c:139) ==31633== by 0x40BAF0: initialise (init.c:48) ==31633== by 0x402299: main (main.c:47) ==31633== Address 0x617140 is 0 bytes inside data symbol "ipv4_miniroutes"
ipv4_miniroutes
is a file-scoped struct list_head
and the supposedly bad code is:
list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
To make things more complicated it only happened with DEBUG=settings
.
All this didn't make much sense until I looked at tap.linux.tmp.map
and found out what symbol is before ipv4_miniroutes
:
0000000000617190 l O .data 0000000000000010 free_blocks 00000000006171a0 g O .data 0000000000000010 .hidden ipv4_miniroutes
Now I knew exactly where to look, core/malloc.c
:
static inline void valgrind_make_blocks_noaccess ( void ) { struct memory_block *block, *tmp; if ( RUNNING_ON_VALGRIND > 0 ) { list_for_each_entry_safe ( block, tmp, &free_blocks, list ) VALGRIND_MAKE_MEM_NOACCESS ( block, sizeof ( *block ) ); VALGRIND_MAKE_MEM_NOACCESS ( block, sizeof ( *block ) ); } }
I got lazy and copy-n-pasted the inner-loop instruction to mark the last item on the list - i.e. free_blocks
as NOACCESS
.
The problem is that free_blocks
is not a struct memory_block
, but struct list_head
and hence the NOACCESS
was marking wrong chunk of the memory, also including part of the ipv4_miniroutes
. Fix:
- VALGRIND_MAKE_MEM_NOACCESS ( block, sizeof ( *block ) ); + VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
drivers in userspace
Working on it while I'm not distracted by other things ;)