mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-18 13:26:48 +07:00
f0907827a8
This adds wrappers for the __builtin overflow checkers present in gcc 5.1+ as well as fallback implementations for earlier compilers. It's not that easy to implement the fully generic __builtin_X_overflow(T1 a, T2 b, T3 *d) in macros, so the fallback code assumes that T1, T2 and T3 are the same. We obviously don't want the wrappers to have different semantics depending on $GCC_VERSION, so we also insist on that even when using the builtins. There are a few problems with the 'a+b < a' idiom for checking for overflow: For signed types, it relies on undefined behaviour and is not actually complete (it doesn't check underflow; e.g. INT_MIN+INT_MIN == 0 isn't caught). Due to type promotion it is wrong for all types (signed and unsigned) narrower than int. Similarly, when a and b does not have the same type, there are subtle cases like u32 a; if (a + sizeof(foo) < a) return -EOVERFLOW; a += sizeof(foo); where the test is always false on 64 bit platforms. Add to that that it is not always possible to determine the types involved at a glance. The new overflow.h is somewhat bulky, but that's mostly a result of trying to be type-generic, complete (e.g. catching not only overflow but also signed underflow) and not relying on undefined behaviour. Linus is of course right [1] that for unsigned subtraction a-b, the right way to check for overflow (underflow) is "b > a" and not "__builtin_sub_overflow(a, b, &d)", but that's just one out of six cases covered here, and included mostly for completeness. So is it worth it? I think it is, if nothing else for the documentation value of seeing if (check_add_overflow(a, b, &d)) return -EGOAWAY; do_stuff_with(d); instead of the open-coded (and possibly wrong and/or incomplete and/or UBsan-tickling) if (a+b < a) return -EGOAWAY; do_stuff_with(a+b); While gcc does recognize the 'a+b < a' idiom for testing unsigned add overflow, it doesn't do nearly as good for unsigned multiplication (there's also no single well-established idiom). So using check_mul_overflow in kcalloc and friends may also make gcc generate slightly better code. [1] https://lkml.org/lkml/2015/11/2/658 Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Signed-off-by: Kees Cook <keescook@chromium.org>
51 lines
1.3 KiB
C
51 lines
1.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __LINUX_COMPILER_TYPES_H
|
|
#error "Please don't include <linux/compiler-intel.h> directly, include <linux/compiler.h> instead."
|
|
#endif
|
|
|
|
#ifdef __ECC
|
|
|
|
/* Some compiler specific definitions are overwritten here
|
|
* for Intel ECC compiler
|
|
*/
|
|
|
|
#include <asm/intrinsics.h>
|
|
|
|
/* Intel ECC compiler doesn't support gcc specific asm stmts.
|
|
* It uses intrinsics to do the equivalent things.
|
|
*/
|
|
#undef barrier
|
|
#undef barrier_data
|
|
#undef RELOC_HIDE
|
|
#undef OPTIMIZER_HIDE_VAR
|
|
|
|
#define barrier() __memory_barrier()
|
|
#define barrier_data(ptr) barrier()
|
|
|
|
#define RELOC_HIDE(ptr, off) \
|
|
({ unsigned long __ptr; \
|
|
__ptr = (unsigned long) (ptr); \
|
|
(typeof(ptr)) (__ptr + (off)); })
|
|
|
|
/* This should act as an optimization barrier on var.
|
|
* Given that this compiler does not have inline assembly, a compiler barrier
|
|
* is the best we can do.
|
|
*/
|
|
#define OPTIMIZER_HIDE_VAR(var) barrier()
|
|
|
|
/* Intel ECC compiler doesn't support __builtin_types_compatible_p() */
|
|
#define __must_be_array(a) 0
|
|
|
|
#endif
|
|
|
|
#ifndef __HAVE_BUILTIN_BSWAP16__
|
|
/* icc has this, but it's called _bswap16 */
|
|
#define __HAVE_BUILTIN_BSWAP16__
|
|
#define __builtin_bswap16 _bswap16
|
|
#endif
|
|
|
|
/*
|
|
* icc defines __GNUC__, but does not implement the builtin overflow checkers.
|
|
*/
|
|
#undef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW
|