From 86d35a8273e98a0d0efd8e3b5dc9eac635c213e7 Mon Sep 17 00:00:00 2001
From: Brandon Maier <brandon.maier@rockwellcollins.com>
Date: Thu, 30 Apr 2020 12:36:53 -0500
Subject: Fix compilation on GCC4 and below

When compiling with GCC4 the following error occurs.

> lib/util/rbtree.c:140: undefined reference to `__builtin_uaddl_overflow'

This is because __builtin_uaddl_overflow() and the other
__builtin_u{add,mul}{,l,ll}_overflow() functions are only defined in
GNUC < 5 for Clang. When using GCC4 and below they are not defined.

Since the SZ_ADD_OV and SZ_MUL_OV are only used to check 'size_t' type
values. And overflow on add and multiply of unsigned types is defined
behaviour (C Standard 6.2.5 paragraph 9). It's simple to write overflow
functions for this specific case. These are based on the overflow
wrappers from the SEI CERT C Standard INT30-C.

[1] https://gcc.gnu.org/gcc-5/changes.html

Signed-off-by: Brandon Maier <brandon.maier@rockwellcollins.com>
---
 include/compat.h | 44 +++++++++++++++++++++++++++-----------------
 1 file changed, 27 insertions(+), 17 deletions(-)

diff --git a/include/compat.h b/include/compat.h
index b2bb054..ee47ef9 100644
--- a/include/compat.h
+++ b/include/compat.h
@@ -9,26 +9,36 @@
 
 #include "sqfs/predef.h"
 
-#if defined(__GNUC__) || defined(__clang__)
-#	if defined(__GNUC__) && __GNUC__ < 5
-#		if SIZEOF_SIZE_T <= SIZEOF_INT
-#			define SZ_ADD_OV __builtin_uadd_overflow
-#			define SZ_MUL_OV __builtin_umul_overflow
-#		elif SIZEOF_SIZE_T == SIZEOF_LONG
-#			define SZ_ADD_OV __builtin_uaddl_overflow
-#			define SZ_MUL_OV __builtin_umull_overflow
-#		elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
-#			define SZ_ADD_OV __builtin_uaddll_overflow
-#			define SZ_MUL_OV __builtin_umulll_overflow
-#		else
-#			error Cannot determine maximum value of size_t
-#		endif
+#if defined(__GNUC__) && __GNUC__ >= 5
+#	define SZ_ADD_OV __builtin_add_overflow
+#	define SZ_MUL_OV __builtin_mul_overflow
+#elif defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5
+#	if SIZEOF_SIZE_T <= SIZEOF_INT
+#		define SZ_ADD_OV __builtin_uadd_overflow
+#		define SZ_MUL_OV __builtin_umul_overflow
+#	elif SIZEOF_SIZE_T == SIZEOF_LONG
+#		define SZ_ADD_OV __builtin_uaddl_overflow
+#		define SZ_MUL_OV __builtin_umull_overflow
+#	elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
+#		define SZ_ADD_OV __builtin_uaddll_overflow
+#		define SZ_MUL_OV __builtin_umulll_overflow
 #	else
-#		define SZ_ADD_OV __builtin_add_overflow
-#		define SZ_MUL_OV __builtin_mul_overflow
+#		error Cannot determine maximum value of size_t
 #	endif
 #else
-#	error I do not know how to trap integer overflows with this compiler
+static inline int _sz_add_overflow(size_t a, size_t b, size_t *res)
+{
+	*res = a + b;
+	return (*res < a) ? 1 : 0;
+}
+
+static inline int _sz_mul_overflow(size_t a, size_t b, size_t *res)
+{
+	*res = a * b;
+	return (b > 0 && (a > SIZE_MAX / b)) ? 1 : 0;
+}
+#	define SZ_ADD_OV _sz_add_overflow
+#	define SZ_MUL_OV _sz_mul_overflow
 #endif
 
 #if defined(_WIN32) || defined(__WINDOWS__)
-- 
cgit v1.2.3