From f661654fad5a42e58d94a339504486a5089250e2 Mon Sep 17 00:00:00 2001
From: Simon McVittie <[EMAIL REDACTED]>
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 <smcv@collabora.com>
---
include/SDL_stdinc.h | 60 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h
index ab1eac66ede..59958ca08c8 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
}