summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas De Marchi <lucas.demarchi@intel.com>2015-02-10 10:41:47 -0200
committerLucas De Marchi <lucas.demarchi@intel.com>2015-02-10 10:43:44 -0200
commitaac5f4514f71d04ac3dcb8b923209781895d7ff2 (patch)
tree48292b9079a0e8989d94aa0cf0c5806b965cbdd9
parent14c3244f04002380d94903b661b93185c158077b (diff)
downloadkmod-aac5f4514f71d04ac3dcb8b923209781895d7ff2.tar.gz
shared: add helper function to add and check for overflow
Use _builtin_uaddll_overflow/_builtin_uaddl_overflow when available, abstracting the type to use it with uint64_t. Otherwise fallback to the implementation as added in 67466f2 ("Prevent offset + size overflow."). This also adds the tests for this new helper in the testsuite.
-rw-r--r--configure.ac2
-rw-r--r--m4/attributes.m42
-rw-r--r--shared/util.h16
-rw-r--r--testsuite/test-util.c19
4 files changed, 39 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 30eea86..30eb37f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,6 +49,8 @@ AC_CHECK_FUNCS_ONCE([finit_module])
CC_CHECK_FUNC_BUILTIN([__builtin_clz])
CC_CHECK_FUNC_BUILTIN([__builtin_types_compatible_p])
+CC_CHECK_FUNC_BUILTIN([__builtin_uaddl_overflow], [ ], [ ])
+CC_CHECK_FUNC_BUILTIN([__builtin_uaddll_overflow], [ ], [ ])
# dietlibc doesn't have st.st_mtim struct member
AC_CHECK_MEMBERS([struct stat.st_mtim], [], [], [#include <sys/stat.h>])
diff --git a/m4/attributes.m4 b/m4/attributes.m4
index 7922746..985a3ed 100644
--- a/m4/attributes.m4
+++ b/m4/attributes.m4
@@ -262,6 +262,8 @@ AC_DEFUN([CC_CHECK_FUNC_BUILTIN], [
m4_case([$1],
[__builtin_clz], [$1(0)],
[__builtin_types_compatible_p], [$1(int, int)],
+ [__builtin_uaddl_overflow], [$1(0UL, 0UL, (void*)0)],
+ [__builtin_uaddll_overflow], [$1(0ULL, 0ULL, (void*)0)],
[__builtin_expect], [$1(0, 0)]
)])],
[cc_cv_have_$1=yes],
diff --git a/shared/util.h b/shared/util.h
index 4c59705..6f602d3 100644
--- a/shared/util.h
+++ b/shared/util.h
@@ -1,5 +1,6 @@
#pragma once
+#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -72,3 +73,18 @@ static inline void freep(void *p) {
free(*(void**) p);
}
#define _cleanup_free_ _cleanup_(freep)
+
+static inline bool addu64_overflow(uint64_t a, uint64_t b, uint64_t *res)
+{
+#if (HAVE___BUILTIN_UADDL_OVERFLOW && HAVE___BUILTIN_UADDLL_OVERFLOW)
+#if __SIZEOF_LONG__ == 8
+ return __builtin_uaddl_overflow(a, b, res);
+#elif __SIZEOF_LONG_LONG__ == 8
+ return __builtin_uaddll_overflow(a, b, res);
+#else
+#error "sizeof(long long) != 8"
+#endif
+#endif
+ *res = a + b;
+ return ULLONG_MAX - a < b;
+}
diff --git a/testsuite/test-util.c b/testsuite/test-util.c
index b0c4ce6..5e25e58 100644
--- a/testsuite/test-util.c
+++ b/testsuite/test-util.c
@@ -206,5 +206,24 @@ DEFINE_TEST(test_write_str_safe,
},
});
+static int test_addu64_overflow(const struct test *t)
+{
+ uint64_t res;
+ bool overflow;
+
+ overflow = addu64_overflow(UINT64_MAX - 1, 1, &res);
+ assert_return(!overflow, EXIT_FAILURE);
+ assert_return(res == UINT64_MAX, EXIT_FAILURE);
+
+ overflow = addu64_overflow(UINT64_MAX, 1, &res);
+ assert_return(overflow, EXIT_FAILURE);
+
+ return EXIT_SUCCESS;
+}
+DEFINE_TEST(test_addu64_overflow,
+ .description = "check implementation of addu4_overflow()",
+ .need_spawn = false,
+ );
+
TESTSUITE_MAIN();