forked from cory/tildefriends
444 lines
25 KiB
C
444 lines
25 KiB
C
|
/*
|
||
|
* Copyright 2021-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||
|
*
|
||
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||
|
* this file except in compliance with the License. You can obtain a copy
|
||
|
* in the file LICENSE in the source distribution or at
|
||
|
* https://www.openssl.org/source/license.html
|
||
|
*/
|
||
|
|
||
|
#ifndef OSSL_INTERNAL_SAFE_MATH_H
|
||
|
# define OSSL_INTERNAL_SAFE_MATH_H
|
||
|
# pragma once
|
||
|
|
||
|
# include <openssl/e_os2.h> /* For 'ossl_inline' */
|
||
|
|
||
|
# ifndef OPENSSL_NO_BUILTIN_OVERFLOW_CHECKING
|
||
|
# ifdef __has_builtin
|
||
|
# define has(func) __has_builtin(func)
|
||
|
# elif __GNUC__ > 5
|
||
|
# define has(func) 1
|
||
|
# endif
|
||
|
# endif /* OPENSSL_NO_BUILTIN_OVERFLOW_CHECKING */
|
||
|
|
||
|
# ifndef has
|
||
|
# define has(func) 0
|
||
|
# endif
|
||
|
|
||
|
/*
|
||
|
* Safe addition helpers
|
||
|
*/
|
||
|
# if has(__builtin_add_overflow)
|
||
|
# define OSSL_SAFE_MATH_ADDS(type_name, type, min, max) \
|
||
|
static ossl_inline ossl_unused type safe_add_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
type r; \
|
||
|
\
|
||
|
if (!__builtin_add_overflow(a, b, &r)) \
|
||
|
return r; \
|
||
|
*err |= 1; \
|
||
|
return a < 0 ? min : max; \
|
||
|
}
|
||
|
|
||
|
# define OSSL_SAFE_MATH_ADDU(type_name, type, max) \
|
||
|
static ossl_inline ossl_unused type safe_add_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
type r; \
|
||
|
\
|
||
|
if (!__builtin_add_overflow(a, b, &r)) \
|
||
|
return r; \
|
||
|
*err |= 1; \
|
||
|
return a + b; \
|
||
|
}
|
||
|
|
||
|
# else /* has(__builtin_add_overflow) */
|
||
|
# define OSSL_SAFE_MATH_ADDS(type_name, type, min, max) \
|
||
|
static ossl_inline ossl_unused type safe_add_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if ((a < 0) ^ (b < 0) \
|
||
|
|| (a > 0 && b <= max - a) \
|
||
|
|| (a < 0 && b >= min - a) \
|
||
|
|| a == 0) \
|
||
|
return a + b; \
|
||
|
*err |= 1; \
|
||
|
return a < 0 ? min : max; \
|
||
|
}
|
||
|
|
||
|
# define OSSL_SAFE_MATH_ADDU(type_name, type, max) \
|
||
|
static ossl_inline ossl_unused type safe_add_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (b > max - a) \
|
||
|
*err |= 1; \
|
||
|
return a + b; \
|
||
|
}
|
||
|
# endif /* has(__builtin_add_overflow) */
|
||
|
|
||
|
/*
|
||
|
* Safe subtraction helpers
|
||
|
*/
|
||
|
# if has(__builtin_sub_overflow)
|
||
|
# define OSSL_SAFE_MATH_SUBS(type_name, type, min, max) \
|
||
|
static ossl_inline ossl_unused type safe_sub_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
type r; \
|
||
|
\
|
||
|
if (!__builtin_sub_overflow(a, b, &r)) \
|
||
|
return r; \
|
||
|
*err |= 1; \
|
||
|
return a < 0 ? min : max; \
|
||
|
}
|
||
|
|
||
|
# else /* has(__builtin_sub_overflow) */
|
||
|
# define OSSL_SAFE_MATH_SUBS(type_name, type, min, max) \
|
||
|
static ossl_inline ossl_unused type safe_sub_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (!((a < 0) ^ (b < 0)) \
|
||
|
|| (b > 0 && a >= min + b) \
|
||
|
|| (b < 0 && a <= max + b) \
|
||
|
|| b == 0) \
|
||
|
return a - b; \
|
||
|
*err |= 1; \
|
||
|
return a < 0 ? min : max; \
|
||
|
}
|
||
|
|
||
|
# endif /* has(__builtin_sub_overflow) */
|
||
|
|
||
|
# define OSSL_SAFE_MATH_SUBU(type_name, type) \
|
||
|
static ossl_inline ossl_unused type safe_sub_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (b > a) \
|
||
|
*err |= 1; \
|
||
|
return a - b; \
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Safe multiplication helpers
|
||
|
*/
|
||
|
# if has(__builtin_mul_overflow)
|
||
|
# define OSSL_SAFE_MATH_MULS(type_name, type, min, max) \
|
||
|
static ossl_inline ossl_unused type safe_mul_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
type r; \
|
||
|
\
|
||
|
if (!__builtin_mul_overflow(a, b, &r)) \
|
||
|
return r; \
|
||
|
*err |= 1; \
|
||
|
return (a < 0) ^ (b < 0) ? min : max; \
|
||
|
}
|
||
|
|
||
|
# define OSSL_SAFE_MATH_MULU(type_name, type, max) \
|
||
|
static ossl_inline ossl_unused type safe_mul_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
type r; \
|
||
|
\
|
||
|
if (!__builtin_mul_overflow(a, b, &r)) \
|
||
|
return r; \
|
||
|
*err |= 1; \
|
||
|
return a * b; \
|
||
|
}
|
||
|
|
||
|
# else /* has(__builtin_mul_overflow) */
|
||
|
# define OSSL_SAFE_MATH_MULS(type_name, type, min, max) \
|
||
|
static ossl_inline ossl_unused type safe_mul_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (a == 0 || b == 0) \
|
||
|
return 0; \
|
||
|
if (a == 1) \
|
||
|
return b; \
|
||
|
if (b == 1) \
|
||
|
return a; \
|
||
|
if (a != min && b != min) { \
|
||
|
const type x = a < 0 ? -a : a; \
|
||
|
const type y = b < 0 ? -b : b; \
|
||
|
\
|
||
|
if (x <= max / y) \
|
||
|
return a * b; \
|
||
|
} \
|
||
|
*err |= 1; \
|
||
|
return (a < 0) ^ (b < 0) ? min : max; \
|
||
|
}
|
||
|
|
||
|
# define OSSL_SAFE_MATH_MULU(type_name, type, max) \
|
||
|
static ossl_inline ossl_unused type safe_mul_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (b != 0 && a > max / b) \
|
||
|
*err |= 1; \
|
||
|
return a * b; \
|
||
|
}
|
||
|
# endif /* has(__builtin_mul_overflow) */
|
||
|
|
||
|
/*
|
||
|
* Safe division helpers
|
||
|
*/
|
||
|
# define OSSL_SAFE_MATH_DIVS(type_name, type, min, max) \
|
||
|
static ossl_inline ossl_unused type safe_div_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (b == 0) { \
|
||
|
*err |= 1; \
|
||
|
return a < 0 ? min : max; \
|
||
|
} \
|
||
|
if (b == -1 && a == min) { \
|
||
|
*err |= 1; \
|
||
|
return max; \
|
||
|
} \
|
||
|
return a / b; \
|
||
|
}
|
||
|
|
||
|
# define OSSL_SAFE_MATH_DIVU(type_name, type, max) \
|
||
|
static ossl_inline ossl_unused type safe_div_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (b != 0) \
|
||
|
return a / b; \
|
||
|
*err |= 1; \
|
||
|
return max; \
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Safe modulus helpers
|
||
|
*/
|
||
|
# define OSSL_SAFE_MATH_MODS(type_name, type, min, max) \
|
||
|
static ossl_inline ossl_unused type safe_mod_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (b == 0) { \
|
||
|
*err |= 1; \
|
||
|
return 0; \
|
||
|
} \
|
||
|
if (b == -1 && a == min) { \
|
||
|
*err |= 1; \
|
||
|
return max; \
|
||
|
} \
|
||
|
return a % b; \
|
||
|
}
|
||
|
|
||
|
# define OSSL_SAFE_MATH_MODU(type_name, type) \
|
||
|
static ossl_inline ossl_unused type safe_mod_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (b != 0) \
|
||
|
return a % b; \
|
||
|
*err |= 1; \
|
||
|
return 0; \
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Safe negation helpers
|
||
|
*/
|
||
|
# define OSSL_SAFE_MATH_NEGS(type_name, type, min) \
|
||
|
static ossl_inline ossl_unused type safe_neg_ ## type_name(type a, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (a != min) \
|
||
|
return -a; \
|
||
|
*err |= 1; \
|
||
|
return min; \
|
||
|
}
|
||
|
|
||
|
# define OSSL_SAFE_MATH_NEGU(type_name, type) \
|
||
|
static ossl_inline ossl_unused type safe_neg_ ## type_name(type a, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (a == 0) \
|
||
|
return a; \
|
||
|
*err |= 1; \
|
||
|
return 1 + ~a; \
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Safe absolute value helpers
|
||
|
*/
|
||
|
# define OSSL_SAFE_MATH_ABSS(type_name, type, min) \
|
||
|
static ossl_inline ossl_unused type safe_abs_ ## type_name(type a, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
if (a != min) \
|
||
|
return a < 0 ? -a : a; \
|
||
|
*err |= 1; \
|
||
|
return min; \
|
||
|
}
|
||
|
|
||
|
# define OSSL_SAFE_MATH_ABSU(type_name, type) \
|
||
|
static ossl_inline ossl_unused type safe_abs_ ## type_name(type a, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
return a; \
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Safe fused multiply divide helpers
|
||
|
*
|
||
|
* These are a bit obscure:
|
||
|
* . They begin by checking the denominator for zero and getting rid of this
|
||
|
* corner case.
|
||
|
*
|
||
|
* . Second is an attempt to do the multiplication directly, if it doesn't
|
||
|
* overflow, the quotient is returned (for signed values there is a
|
||
|
* potential problem here which isn't present for unsigned).
|
||
|
*
|
||
|
* . Finally, the multiplication/division is transformed so that the larger
|
||
|
* of the numerators is divided first. This requires a remainder
|
||
|
* correction:
|
||
|
*
|
||
|
* a b / c = (a / c) b + (a mod c) b / c, where a > b
|
||
|
*
|
||
|
* The individual operations need to be overflow checked (again signed
|
||
|
* being more problematic).
|
||
|
*
|
||
|
* The algorithm used is not perfect but it should be "good enough".
|
||
|
*/
|
||
|
# define OSSL_SAFE_MATH_MULDIVS(type_name, type, max) \
|
||
|
static ossl_inline ossl_unused type safe_muldiv_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
type c, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
int e2 = 0; \
|
||
|
type q, r, x, y; \
|
||
|
\
|
||
|
if (c == 0) { \
|
||
|
*err |= 1; \
|
||
|
return a == 0 || b == 0 ? 0 : max; \
|
||
|
} \
|
||
|
x = safe_mul_ ## type_name(a, b, &e2); \
|
||
|
if (!e2) \
|
||
|
return safe_div_ ## type_name(x, c, err); \
|
||
|
if (b > a) { \
|
||
|
x = b; \
|
||
|
b = a; \
|
||
|
a = x; \
|
||
|
} \
|
||
|
q = safe_div_ ## type_name(a, c, err); \
|
||
|
r = safe_mod_ ## type_name(a, c, err); \
|
||
|
x = safe_mul_ ## type_name(r, b, err); \
|
||
|
y = safe_mul_ ## type_name(q, b, err); \
|
||
|
q = safe_div_ ## type_name(x, c, err); \
|
||
|
return safe_add_ ## type_name(y, q, err); \
|
||
|
}
|
||
|
|
||
|
# define OSSL_SAFE_MATH_MULDIVU(type_name, type, max) \
|
||
|
static ossl_inline ossl_unused type safe_muldiv_ ## type_name(type a, \
|
||
|
type b, \
|
||
|
type c, \
|
||
|
int *err) \
|
||
|
{ \
|
||
|
int e2 = 0; \
|
||
|
type x, y; \
|
||
|
\
|
||
|
if (c == 0) { \
|
||
|
*err |= 1; \
|
||
|
return a == 0 || b == 0 ? 0 : max; \
|
||
|
} \
|
||
|
x = safe_mul_ ## type_name(a, b, &e2); \
|
||
|
if (!e2) \
|
||
|
return x / c; \
|
||
|
if (b > a) { \
|
||
|
x = b; \
|
||
|
b = a; \
|
||
|
a = x; \
|
||
|
} \
|
||
|
x = safe_mul_ ## type_name(a % c, b, err); \
|
||
|
y = safe_mul_ ## type_name(a / c, b, err); \
|
||
|
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))
|
||
|
# define OSSL_SAFE_MATH_MAXU(type) (~(type)0)
|
||
|
|
||
|
/*
|
||
|
* Wrapper macros to create all the functions of a given type
|
||
|
*/
|
||
|
# define OSSL_SAFE_MATH_SIGNED(type_name, type) \
|
||
|
OSSL_SAFE_MATH_ADDS(type_name, type, OSSL_SAFE_MATH_MINS(type), \
|
||
|
OSSL_SAFE_MATH_MAXS(type)) \
|
||
|
OSSL_SAFE_MATH_SUBS(type_name, type, OSSL_SAFE_MATH_MINS(type), \
|
||
|
OSSL_SAFE_MATH_MAXS(type)) \
|
||
|
OSSL_SAFE_MATH_MULS(type_name, type, OSSL_SAFE_MATH_MINS(type), \
|
||
|
OSSL_SAFE_MATH_MAXS(type)) \
|
||
|
OSSL_SAFE_MATH_DIVS(type_name, type, OSSL_SAFE_MATH_MINS(type), \
|
||
|
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))
|
||
|
|
||
|
# define OSSL_SAFE_MATH_UNSIGNED(type_name, type) \
|
||
|
OSSL_SAFE_MATH_ADDU(type_name, type, OSSL_SAFE_MATH_MAXU(type)) \
|
||
|
OSSL_SAFE_MATH_SUBU(type_name, type) \
|
||
|
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)
|
||
|
|
||
|
#endif /* OSSL_INTERNAL_SAFE_MATH_H */
|