summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorPauli <pauli@openssl.org>2022-03-15 14:19:07 +1100
committerPauli <pauli@openssl.org>2022-03-30 10:10:25 +1100
commit4157a32867e6643da8daee94e836aaa18b9feed6 (patch)
treeed00f2727a856b8313d108de65940d8d527868f1 /include
parent5d3746910438fd052b44010d92ac70fea606fa9d (diff)
Add a divide rounding up safe math function.
This function takes arguments a & b and computes a / b rounding any remainder up. It is safe with respect to overflow and negative inputs. It's only fast for non-negative inputs. Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/17884)
Diffstat (limited to 'include')
-rw-r--r--include/internal/safe_math.h38
1 files changed, 38 insertions, 0 deletions
diff --git a/include/internal/safe_math.h b/include/internal/safe_math.h
index 85c6147e55..d14a090b24 100644
--- a/include/internal/safe_math.h
+++ b/include/internal/safe_math.h
@@ -369,6 +369,40 @@
return safe_add_ ## type_name(y, x / c, err); \
}
+/*
+ * Calculate a / b rounding up:
+ * i.e. a / b + (a % b != 0)
+ * Which is usually (less safely) converted to (a + b - 1) / b
+ * If you *know* that b != 0, then it's safe to ignore err.
+ */
+#define OSSL_SAFE_MATH_DIV_ROUND_UP(type_name, type, max) \
+ static ossl_inline ossl_unused type safe_div_round_up_ ## type_name \
+ (type a, type b, int *errp) \
+ { \
+ type x; \
+ int *err, err_local = 0; \
+ \
+ /* Allow errors to be ignored by callers */ \
+ err = errp != NULL ? errp : &err_local; \
+ /* Fast path, both positive */ \
+ if (b > 0 && a > 0) { \
+ /* Faster path: no overflow concerns */ \
+ if (a < max - b) \
+ return (a + b - 1) / b; \
+ return a / b + (a % b != 0); \
+ } \
+ if (b == 0) { \
+ *err |= 1; \
+ return a == 0 ? 0 : max; \
+ } \
+ if (a == 0) \
+ return 0; \
+ /* Rather slow path because there are negatives involved */ \
+ x = safe_mod_ ## type_name(a, b, err); \
+ return safe_add_ ## type_name(safe_div_ ## type_name(a, b, err), \
+ x != 0, err); \
+ }
+
/* Calculate ranges of types */
# define OSSL_SAFE_MATH_MINS(type) ((type)1 << (sizeof(type) * 8 - 1))
# define OSSL_SAFE_MATH_MAXS(type) (~OSSL_SAFE_MATH_MINS(type))
@@ -388,6 +422,8 @@
OSSL_SAFE_MATH_MAXS(type)) \
OSSL_SAFE_MATH_MODS(type_name, type, OSSL_SAFE_MATH_MINS(type), \
OSSL_SAFE_MATH_MAXS(type)) \
+ OSSL_SAFE_MATH_DIV_ROUND_UP(type_name, type, \
+ OSSL_SAFE_MATH_MAXS(type)) \
OSSL_SAFE_MATH_MULDIVS(type_name, type, OSSL_SAFE_MATH_MAXS(type)) \
OSSL_SAFE_MATH_NEGS(type_name, type, OSSL_SAFE_MATH_MINS(type)) \
OSSL_SAFE_MATH_ABSS(type_name, type, OSSL_SAFE_MATH_MINS(type))
@@ -398,6 +434,8 @@
OSSL_SAFE_MATH_MULU(type_name, type, OSSL_SAFE_MATH_MAXU(type)) \
OSSL_SAFE_MATH_DIVU(type_name, type, OSSL_SAFE_MATH_MAXU(type)) \
OSSL_SAFE_MATH_MODU(type_name, type) \
+ OSSL_SAFE_MATH_DIV_ROUND_UP(type_name, type, \
+ OSSL_SAFE_MATH_MAXU(type)) \
OSSL_SAFE_MATH_MULDIVU(type_name, type, OSSL_SAFE_MATH_MAXU(type)) \
OSSL_SAFE_MATH_NEGU(type_name, type) \
OSSL_SAFE_MATH_ABSU(type_name, type)