![Pekka Enberg](/assets/img/avatar_default.png)
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: Ingo Molnar <mingo@elte.hu> Acked-by: Ingo Molnar <mingo@elte.hu> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
161 lines
4.2 KiB
C
161 lines
4.2 KiB
C
#ifndef LINUX_KMEMCHECK_H
|
|
#define LINUX_KMEMCHECK_H
|
|
|
|
#include <linux/mm_types.h>
|
|
#include <linux/types.h>
|
|
|
|
#ifdef CONFIG_KMEMCHECK
|
|
extern int kmemcheck_enabled;
|
|
|
|
/* The slab-related functions. */
|
|
void kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node);
|
|
void kmemcheck_free_shadow(struct page *page, int order);
|
|
void kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object,
|
|
size_t size);
|
|
void kmemcheck_slab_free(struct kmem_cache *s, void *object, size_t size);
|
|
|
|
void kmemcheck_pagealloc_alloc(struct page *p, unsigned int order,
|
|
gfp_t gfpflags);
|
|
|
|
void kmemcheck_show_pages(struct page *p, unsigned int n);
|
|
void kmemcheck_hide_pages(struct page *p, unsigned int n);
|
|
|
|
bool kmemcheck_page_is_tracked(struct page *p);
|
|
|
|
void kmemcheck_mark_unallocated(void *address, unsigned int n);
|
|
void kmemcheck_mark_uninitialized(void *address, unsigned int n);
|
|
void kmemcheck_mark_initialized(void *address, unsigned int n);
|
|
void kmemcheck_mark_freed(void *address, unsigned int n);
|
|
|
|
void kmemcheck_mark_unallocated_pages(struct page *p, unsigned int n);
|
|
void kmemcheck_mark_uninitialized_pages(struct page *p, unsigned int n);
|
|
void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n);
|
|
|
|
int kmemcheck_show_addr(unsigned long address);
|
|
int kmemcheck_hide_addr(unsigned long address);
|
|
|
|
bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size);
|
|
|
|
#else
|
|
#define kmemcheck_enabled 0
|
|
|
|
static inline void
|
|
kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node)
|
|
{
|
|
}
|
|
|
|
static inline void
|
|
kmemcheck_free_shadow(struct page *page, int order)
|
|
{
|
|
}
|
|
|
|
static inline void
|
|
kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object,
|
|
size_t size)
|
|
{
|
|
}
|
|
|
|
static inline void kmemcheck_slab_free(struct kmem_cache *s, void *object,
|
|
size_t size)
|
|
{
|
|
}
|
|
|
|
static inline void kmemcheck_pagealloc_alloc(struct page *p,
|
|
unsigned int order, gfp_t gfpflags)
|
|
{
|
|
}
|
|
|
|
static inline bool kmemcheck_page_is_tracked(struct page *p)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline void kmemcheck_mark_unallocated(void *address, unsigned int n)
|
|
{
|
|
}
|
|
|
|
static inline void kmemcheck_mark_uninitialized(void *address, unsigned int n)
|
|
{
|
|
}
|
|
|
|
static inline void kmemcheck_mark_initialized(void *address, unsigned int n)
|
|
{
|
|
}
|
|
|
|
static inline void kmemcheck_mark_freed(void *address, unsigned int n)
|
|
{
|
|
}
|
|
|
|
static inline void kmemcheck_mark_unallocated_pages(struct page *p,
|
|
unsigned int n)
|
|
{
|
|
}
|
|
|
|
static inline void kmemcheck_mark_uninitialized_pages(struct page *p,
|
|
unsigned int n)
|
|
{
|
|
}
|
|
|
|
static inline void kmemcheck_mark_initialized_pages(struct page *p,
|
|
unsigned int n)
|
|
{
|
|
}
|
|
|
|
static inline bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
#endif /* CONFIG_KMEMCHECK */
|
|
|
|
/*
|
|
* Bitfield annotations
|
|
*
|
|
* How to use: If you have a struct using bitfields, for example
|
|
*
|
|
* struct a {
|
|
* int x:8, y:8;
|
|
* };
|
|
*
|
|
* then this should be rewritten as
|
|
*
|
|
* struct a {
|
|
* kmemcheck_bitfield_begin(flags);
|
|
* int x:8, y:8;
|
|
* kmemcheck_bitfield_end(flags);
|
|
* };
|
|
*
|
|
* Now the "flags_begin" and "flags_end" members may be used to refer to the
|
|
* beginning and end, respectively, of the bitfield (and things like
|
|
* &x.flags_begin is allowed). As soon as the struct is allocated, the bit-
|
|
* fields should be annotated:
|
|
*
|
|
* struct a *a = kmalloc(sizeof(struct a), GFP_KERNEL);
|
|
* kmemcheck_annotate_bitfield(a, flags);
|
|
*
|
|
* Note: We provide the same definitions for both kmemcheck and non-
|
|
* kmemcheck kernels. This makes it harder to introduce accidental errors. It
|
|
* is also allowed to pass NULL pointers to kmemcheck_annotate_bitfield().
|
|
*/
|
|
#define kmemcheck_bitfield_begin(name) \
|
|
int name##_begin[0];
|
|
|
|
#define kmemcheck_bitfield_end(name) \
|
|
int name##_end[0];
|
|
|
|
#define kmemcheck_annotate_bitfield(ptr, name) \
|
|
do if (ptr) { \
|
|
int _n = (long) &((ptr)->name##_end) \
|
|
- (long) &((ptr)->name##_begin); \
|
|
BUILD_BUG_ON(_n < 0); \
|
|
\
|
|
kmemcheck_mark_initialized(&((ptr)->name##_begin), _n); \
|
|
} while (0)
|
|
|
|
#define kmemcheck_annotate_variable(var) \
|
|
do { \
|
|
kmemcheck_mark_initialized(&(var), sizeof(var)); \
|
|
} while (0) \
|
|
|
|
#endif /* LINUX_KMEMCHECK_H */
|