[1/6] eal: add portable way to check for math overflow

Message ID 20200303175938.14292-2-stephen@networkplumber.org (mailing list archive)
State Changes Requested, archived
Delegated to: Ajit Khaparde
Headers
Series net/bnxt: bounds checking patches |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/iol-testing success Testing PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/Intel-compilation success Compilation OK

Commit Message

Stephen Hemminger March 3, 2020, 5:59 p.m. UTC
  Clang and recent versions of GCC has builtin functions to do most math
operations and check for wraparound. On most architectures this is a
just a math operation followed by a branch on carry set.

But DPDK needs to be able to handle older GCC versions, and other
compilers so a wrapper macro is needed.

Chose to use a macro instead of inline functions to avoid having
to write lots of variants for each numeric type.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/librte_eal/common/Makefile               |  2 +-
 lib/librte_eal/common/include/rte_overflow.h | 74 ++++++++++++++++++++
 2 files changed, 75 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/include/rte_overflow.h
  

Comments

Dmitry Kozlyuk March 3, 2020, 10:28 p.m. UTC | #1
> +#if defined(__has_builtin)
> +#    if __has_builtin(__builtin_add_overflow)
> +#        define RTE_HAVE_BUILTIN_OVERFLOW
> +#    endif
> +#elif defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION >= 5000)
> +#    define RTE__HAVE_BUILTIN_OVERFLOW

Excessive underline after RTE results in RTE_HAVE_BUILTIN_OVERFLOW not being
defined.
  

Patch

diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index c2c6d92cd377..3794128b75b7 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -13,7 +13,7 @@  INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
-INC += rte_option.h
+INC += rte_option.h rte_overflow.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/include/rte_overflow.h b/lib/librte_eal/common/include/rte_overflow.h
new file mode 100644
index 000000000000..d61791371029
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_overflow.h
@@ -0,0 +1,74 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Microsoft Corp
+ */
+#ifndef RTE_OVERFLOW_H_
+#define RTE_OVERFLOW_H_
+/**
+ * @file
+ *
+ * Math functions with overflow checking.
+ * Wrappers for the __builtin_XXX_overflow functions that exist
+ * in recent versions of GCC and CLANG but may not exist
+ * in older compilers. They are macros to allow use with any
+ * size of unsigned number.
+ *
+ * See:
+ *  https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html
+ *  https://github.com/nemequ/portable-snippets/tree/master/safe-math
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+#if defined(__has_builtin)
+#    if __has_builtin(__builtin_add_overflow)
+#        define RTE_HAVE_BUILTIN_OVERFLOW
+#    endif
+#elif defined(RTE_TOOLCHAIN_GCC) && (GCC_VERSION >= 5000)
+#    define RTE__HAVE_BUILTIN_OVERFLOW
+#endif
+
+/**
+ * Safely add two bit unsigned numbers
+ * @param a
+ *   One operand
+ * @param b
+ *   Other operand
+ * @param res
+ *   Pointer to the where result of a + b is stored.
+ *   Must not be NULL
+ * @return
+ *   return true if the result overflows and is therefore truncated.
+ */
+#ifdef RTE_HAVE_BUILTIN_OVERFLOW
+#define rte_add_overflow(a, b, res) __builtin_add_overflow(a, b, res)
+#else
+#define rte_add_overflow(a, b, res) ({ *res = a + b; *res < a; })
+#endif
+
+/**
+ * Safely multiply two unsigned numbers
+ * @param a
+ *   One operand
+ * @param b
+ *   Other operand
+ * @param res
+ *   Pointer to the where result of a + b is stored.
+ *   Must not be NULL
+ * @return
+ *   return true if the result overflows and is therefore truncated.
+ */
+#ifdef RTE_HAVE_BUILTIN_OVERFLOW
+#define rte_mul_overflow(a, b, res) __builtin_mul_overflow(a, b, res)
+#else
+#define rte_mul_overflow(a, b, res) ({ *res = a * b; *res < a; })
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_OVERFLOW_H_ */