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


QR Code
QR Code soc:2010:peper:journal:week8 (generated for current page)