From f661654fad5a42e58d94a339504486a5089250e2 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 9 May 2022 14:36:27 +0100 Subject: [PATCH] stdinc: Add overflow-checking add and multiply for size_t This can be used to check whether untrusted sizes would cause overflow when used to calculate how much memory is needed. Signed-off-by: Simon McVittie --- include/SDL_stdinc.h | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h index ab1eac66e..59958ca08 100644 --- a/include/SDL_stdinc.h +++ b/include/SDL_stdinc.h @@ -115,6 +115,12 @@ char *alloca(); # endif #endif +#ifdef SIZE_MAX +# define SDL_SIZE_MAX SIZE_MAX +#else +# define SDL_SIZE_MAX ((size_t) -1) +#endif + /** * Check if the compiler supports a given builtin. * Supported by virtually all clang versions and recent gcc. Use this @@ -728,6 +734,60 @@ SDL_FORCE_INLINE void *SDL_memcpy4(SDL_OUT_BYTECAP(dwords*4) void *dst, SDL_IN_B return SDL_memcpy(dst, src, dwords * 4); } +/** + * If a * b would overflow, return -1. Otherwise store a * b via ret + * and return 0. + * + * \since This function is available since SDL 2.24.0. + */ +SDL_FORCE_INLINE int SDL_size_mul_overflow (size_t a, + size_t b, + size_t *ret) +{ + if (a != 0 && b > SDL_SIZE_MAX / a) { + return -1; + } + *ret = a * b; + return 0; +} + +#if _SDL_HAS_BUILTIN(__builtin_mul_overflow) +SDL_FORCE_INLINE int _SDL_size_mul_overflow_builtin (size_t a, + size_t b, + size_t *ret) +{ + return __builtin_mul_overflow(a, b, ret) == 0 ? 0 : -1; +} +#define SDL_size_mul_overflow(a, b, ret) (_SDL_size_mul_overflow_builtin(a, b, ret)) +#endif + +/** + * If a + b would overflow, return -1. Otherwise store a + b via ret + * and return 0. + * + * \since This function is available since SDL 2.24.0. + */ +SDL_FORCE_INLINE int SDL_size_add_overflow (size_t a, + size_t b, + size_t *ret) +{ + if (b > SDL_SIZE_MAX - a) { + return -1; + } + *ret = a + b; + return 0; +} + +#if _SDL_HAS_BUILTIN(__builtin_add_overflow) +SDL_FORCE_INLINE int _SDL_size_add_overflow_builtin (size_t a, + size_t b, + size_t *ret) +{ + return __builtin_add_overflow(a, b, ret) == 0 ? 0 : -1; +} +#define SDL_size_add_overflow(a, b, ret) (_SDL_size_add_overflow_builtin(a, b, ret)) +#endif + /* Ends C function definitions when using C++ */ #ifdef __cplusplus }