diff options
author | Pauli <pauli@openssl.org> | 2022-03-15 14:19:07 +1100 |
---|---|---|
committer | Pauli <pauli@openssl.org> | 2022-03-30 10:10:25 +1100 |
commit | 4157a32867e6643da8daee94e836aaa18b9feed6 (patch) | |
tree | ed00f2727a856b8313d108de65940d8d527868f1 /include | |
parent | 5d3746910438fd052b44010d92ac70fea606fa9d (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.h | 38 |
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) |