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

Commit e992cd9b authored by Vegard Nossum's avatar Vegard Nossum Committed by Linus Torvalds
Browse files

kmemcheck: make bitfield annotations truly no-ops when disabled



It turns out that even zero-sized struct members (int foo[0];) will affect
the struct layout, causing us in particular to lose 4 bytes in struct
sock.

This patch fixes the regression in CONFIG_KMEMCHECK=n case.

Reported-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarVegard Nossum <vegard.nossum@gmail.com>
Acked-by: default avatarPekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent cb5a8b2c
Loading
Loading
Loading
Loading
+58 −52
Original line number Diff line number Diff line
@@ -36,6 +36,56 @@ int kmemcheck_hide_addr(unsigned long address);

bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size);

/*
 * 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);
 */
#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 {								\
		int _n;							\
									\
		if (!ptr)						\
			break;						\
									\
		_n = (long) &((ptr)->name##_end)			\
			- (long) &((ptr)->name##_begin);		\
		MAYBE_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)							\

#else
#define kmemcheck_enabled 0

@@ -106,60 +156,16 @@ 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_bitfield_begin(name)
#define kmemcheck_bitfield_end(name)
#define kmemcheck_annotate_bitfield(ptr, name)	\
	do {					\
		int _n;							\
									\
		if (!ptr)						\
			break;						\
									\
		_n = (long) &((ptr)->name##_end)			\
			- (long) &((ptr)->name##_begin);		\
		MAYBE_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)							\
	} while (0)

#endif /* CONFIG_KMEMCHECK */

#endif /* LINUX_KMEMCHECK_H */