/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2020 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see .
*
* Arithmetic operations that protect against overflow.
*/
#ifndef GRUB_SAFEMATH_H
#define GRUB_SAFEMATH_H 1
#include
/* These appear in gcc 5.1 and clang 3.8. */
#if GNUC_PREREQ(5, 1) || CLANG_PREREQ(3, 8)
#define grub_add(a, b, res) __builtin_add_overflow(a, b, res)
#define grub_sub(a, b, res) __builtin_sub_overflow(a, b, res)
#define grub_mul(a, b, res) __builtin_mul_overflow(a, b, res)
#else
/*
* Copyright 2020 Rasmus Villemoes
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/*
* The code used in this header was taken from linux kernel commit
* f0907827a8a9152aedac2833ed1b674a7b2a44f2
* Rasmus Villemoes , the original author of the
* patch, was contacted directly, confirmed his authorship of the code, and
* gave his permission on treating that dual license as MIT and including into
* GRUB2 sources
*/
#include
#define is_signed_type(type) (((type)(-1)) < (type)1)
#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
#define type_min(T) ((T)((T)-type_max(T)-(T)1))
#define __unsigned_add_overflow(a, b, d) ({ \
typeof(+(a)) __a = (a); \
typeof(+(b)) __b = (b); \
typeof(d) __d = (d); \
(void) (&__a == &__b); \
(void) (&__a == __d); \
*__d = __a + __b; \
*__d < __a; \
})
#define __unsigned_sub_overflow(a, b, d) ({ \
typeof(+(a)) __a = (a); \
typeof(+(b)) __b = (b); \
typeof(d) __d = (d); \
(void) (&__a == &__b); \
(void) (&__a == __d); \
*__d = __a - __b; \
__a < __b; \
})
#define __unsigned_mul_overflow(a, b, d) ({ \
typeof(+(a)) __a = (a); \
typeof(+(b)) __b = (b); \
typeof(d) __d = (d); \
(void) (&__a == &__b); \
(void) (&__a == __d); \
*__d = __a * __b; \
__builtin_constant_p(__b) ? \
__b > 0 && __a > type_max(typeof(__a)) / __b :\
__a > 0 && __b > type_max(typeof(__b)) / __a; \
})
#define __signed_add_overflow(a, b, d) ({ \
typeof(+(a)) __a = (a); \
typeof(+(b)) __b = (b); \
typeof(d) __d = (d); \
(void) (&__a == &__b); \
(void) (&__a == __d); \
*__d = (grub_uint64_t)__a + (grub_uint64_t)__b; \
(((~(__a ^ __b)) & (*__d ^ __a)) \
& type_min(typeof(__a))) != 0; \
})
#define __signed_sub_overflow(a, b, d) ({ \
typeof(+(a)) __a = (a); \
typeof(+(b)) __b = (b); \
typeof(d) __d = (d); \
(void) (&__a == &__b); \
(void) (&__a == __d); \
*__d = (grub_uint64_t)__a - (grub_uint64_t)__b; \
((((__a ^ __b)) & (*__d ^ __a)) \
& type_min(typeof(__a))) != 0; \
})
#define __signed_mul_overflow(a, b, d) ({ \
typeof(+(a)) __a = (a); \
typeof(+(b)) __b = (b); \
typeof(d) __d = (d); \
typeof(+(a)) __tmax = type_max(typeof(+(a))); \
typeof(+(a)) __tmin = type_min(typeof(+(a))); \
(void) (&__a == &__b); \
(void) (&__a == __d); \
*__d = (grub_uint64_t)__a * (grub_uint64_t)__b; \
(__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) ||\
(__b < (typeof(__b))-1 && \
(__a > __tmin/__b || __a < __tmax/__b)) || \
(__b == (typeof(__b))-1 && __a == __tmin); \
})
#define grub_add(a, b, d) \
__builtin_choose_expr(is_signed_type(typeof(+(a))), \
__signed_add_overflow(a, b, d), \
__unsigned_add_overflow(a, b, d))
#define grub_sub(a, b, d) \
__builtin_choose_expr(is_signed_type(typeof(+(a))), \
__signed_sub_overflow(a, b, d), \
__unsigned_sub_overflow(a, b, d))
#define grub_mul(a, b, d) \
__builtin_choose_expr(is_signed_type(typeof(+(a))), \
__signed_mul_overflow(a, b, d), \
__unsigned_mul_overflow(a, b, d))
#endif
#endif /* GRUB_SAFEMATH_H */