Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e019366 authored by Pekka Enberg's avatar Pekka Enberg Committed by Catalin Marinas
Browse files

kmemleak: Don't scan uninitialized memory when kmemcheck is enabled



Ingo Molnar reported the following kmemcheck warning when running both
kmemleak and kmemcheck enabled:

  PM: Adding info for No Bus:vcsa7
  WARNING: kmemcheck: Caught 32-bit read from uninitialized memory
  (f6f6e1a4)
  d873f9f600000000c42ae4c1005c87f70000000070665f666978656400000000
   i i i i u u u u i i i i i i i i i i i i i i i i i i i i i u u u
           ^

  Pid: 3091, comm: kmemleak Not tainted (2.6.31-rc7-tip #1303) P4DC6
  EIP: 0060:[<c110301f>] EFLAGS: 00010006 CPU: 0
  EIP is at scan_block+0x3f/0xe0
  EAX: f40bd700 EBX: f40bd780 ECX: f16b46c0 EDX: 00000001
  ESI: f6f6e1a4 EDI: 00000000 EBP: f10f3f4c ESP: c2605fcc
   DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
  CR0: 8005003b CR2: e89a4844 CR3: 30ff1000 CR4: 000006f0
  DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
  DR6: ffff4ff0 DR7: 00000400
   [<c110313c>] scan_object+0x7c/0xf0
   [<c1103389>] kmemleak_scan+0x1d9/0x400
   [<c1103a3c>] kmemleak_scan_thread+0x4c/0xb0
   [<c10819d4>] kthread+0x74/0x80
   [<c10257db>] kernel_thread_helper+0x7/0x3c
   [<ffffffff>] 0xffffffff
  kmemleak: 515 new suspected memory leaks (see
  /sys/kernel/debug/kmemleak)
  kmemleak: 42 new suspected memory leaks (see /sys/kernel/debug/kmemleak)

The problem here is that kmemleak will scan partially initialized
objects that makes kmemcheck complain. Fix that up by skipping
uninitialized memory regions when kmemcheck is enabled.

Reported-by: default avatarIngo Molnar <mingo@elte.hu>
Acked-by: default avatarIngo Molnar <mingo@elte.hu>
Acked-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarPekka Enberg <penberg@cs.helsinki.fi>
parent acde31dc
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -331,6 +331,20 @@ static void kmemcheck_read_strict(struct pt_regs *regs,
	kmemcheck_shadow_set(shadow, size);
	kmemcheck_shadow_set(shadow, size);
}
}


bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size)
{
	enum kmemcheck_shadow status;
	void *shadow;

	shadow = kmemcheck_shadow_lookup(addr);
	if (!shadow)
		return true;

	status = kmemcheck_shadow_test(shadow, size);

	return status == KMEMCHECK_SHADOW_INITIALIZED;
}

/* Access may cross page boundary */
/* Access may cross page boundary */
static void kmemcheck_read(struct pt_regs *regs,
static void kmemcheck_read(struct pt_regs *regs,
	unsigned long addr, unsigned int size)
	unsigned long addr, unsigned int size)
+7 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,8 @@ void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n);
int kmemcheck_show_addr(unsigned long address);
int kmemcheck_show_addr(unsigned long address);
int kmemcheck_hide_addr(unsigned long address);
int kmemcheck_hide_addr(unsigned long address);


bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size);

#else
#else
#define kmemcheck_enabled 0
#define kmemcheck_enabled 0


@@ -99,6 +101,11 @@ static inline void kmemcheck_mark_initialized_pages(struct page *p,
{
{
}
}


static inline bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size)
{
	return true;
}

#endif /* CONFIG_KMEMCHECK */
#endif /* CONFIG_KMEMCHECK */


/*
/*
+10 −2
Original line number Original line Diff line number Diff line
@@ -97,6 +97,7 @@
#include <asm/processor.h>
#include <asm/processor.h>
#include <asm/atomic.h>
#include <asm/atomic.h>


#include <linux/kmemcheck.h>
#include <linux/kmemleak.h>
#include <linux/kmemleak.h>


/*
/*
@@ -967,15 +968,22 @@ static void scan_block(void *_start, void *_end,
	unsigned long *end = _end - (BYTES_PER_POINTER - 1);
	unsigned long *end = _end - (BYTES_PER_POINTER - 1);


	for (ptr = start; ptr < end; ptr++) {
	for (ptr = start; ptr < end; ptr++) {
		unsigned long flags;
		unsigned long pointer = *ptr;
		struct kmemleak_object *object;
		struct kmemleak_object *object;
		unsigned long flags;
		unsigned long pointer;


		if (allow_resched)
		if (allow_resched)
			cond_resched();
			cond_resched();
		if (scan_should_stop())
		if (scan_should_stop())
			break;
			break;


		/* don't scan uninitialized memory */
		if (!kmemcheck_is_obj_initialized((unsigned long)ptr,
						  BYTES_PER_POINTER))
			continue;

		pointer = *ptr;

		object = find_and_get_object(pointer, 1);
		object = find_and_get_object(pointer, 1);
		if (!object)
		if (!object)
			continue;
			continue;