Adorning functions allocating dynamic memory with __alloc_size allows GCC to warn about heap overflows it notices during normal compilation. Import the definitions from Linux and switch over barebox <malloc.h> to make use of it. Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> --- include/linux/compiler-gcc.h | 8 ++++++++ include/linux/compiler_types.h | 24 ++++++++++++++++++++++++ include/malloc.h | 9 +++++---- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 4d36b27214fd..2534386d040f 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -234,3 +234,11 @@ #else #define __diag_GCC_8(s) #endif + +/* + * Prior to 9.1, -Wno-alloc-size-larger-than (and therefore the "alloc_size" + * attribute) do not work, and must be disabled. + */ +#if GCC_VERSION < 90100 +#undef __alloc_size__ +#endif diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 800bc518feea..9ef8115a396f 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -56,6 +56,16 @@ extern void __chk_io_ptr(const volatile void __iomem *); #ifdef __KERNEL__ +/* + * Note: do not use this directly. Instead, use __alloc_size() since it is conditionally + * available and includes other attributes. For GCC < 9.1, __alloc_size__ gets undefined + * in compiler-gcc.h, due to misbehaviors. + * + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-alloc_005fsize-function-attribute + * clang: https://clang.llvm.org/docs/AttributeReference.html#alloc-size + */ +#define __alloc_size__(x, ...) __attribute__((__alloc_size__(x, ## __VA_ARGS__))) + /* Compiler specific macros. */ #ifdef __clang__ #include <linux/compiler-clang.h> @@ -188,6 +198,20 @@ struct ftrace_likely_data { #define __assume_aligned(a, ...) #endif +/* + * Any place that could be marked with the "alloc_size" attribute is also + * a place to be marked with the "malloc" attribute, except those that may + * be performing a _reallocation_, as that may alias the existing pointer. + * For these, use __realloc_size(). + */ +#ifdef __alloc_size__ +# define __alloc_size(x, ...) __alloc_size__(x, ## __VA_ARGS__) __malloc +# define __realloc_size(x, ...) __alloc_size__(x, ## __VA_ARGS__) +#else +# define __alloc_size(x, ...) __malloc +# define __realloc_size(x, ...) +#endif + /* Are two types/vars the same type (ignoring qualifiers)? */ #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) diff --git a/include/malloc.h b/include/malloc.h index 971fc4058bc6..d63853b91e91 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -2,13 +2,14 @@ #ifndef __MALLOC_H #define __MALLOC_H +#include <linux/compiler.h> #include <types.h> -void *malloc(size_t); +void *malloc(size_t) __alloc_size(1); void free(void *); -void *realloc(void *, size_t); -void *memalign(size_t, size_t); -void *calloc(size_t, size_t); +void *realloc(void *, size_t) __realloc_size(2); +void *memalign(size_t, size_t) __alloc_size(2); +void *calloc(size_t, size_t) __alloc_size(1, 2); void malloc_stats(void); void *sbrk(ptrdiff_t increment); -- 2.39.2