====== 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 ;)