123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- // SPDX-License-Identifier: GPL-3.0-or-later
- // Copyright © 2018-2019 Ariadne Devos
- /* sHT -- compare values, on a Spectre-oblivious compiler */
- #ifndef _sHT_TEST_H
- #define _sHT_TEST_H
- #include <stddef.h>
- #include <stdint.h>
- #include <sHT/compiler.h>
- #include <sHT/test-arch.h>
- /** Comparing values
- If two values are compared, the compiler can assume information in both
- branches, which may be -- speculatively -- incorrect. s2 must not allow
- side-channel attacks.
- Why use inline assembly instead of littering the code with
- @var{sHT_hide_var}? Because its a lie that the variable changes,
- reducing optimisation opportunities, because its fragile: information
- about a parameter implies information about other data, because it is
- less verbose, and because branches can easily be marked.
- The last allows for checking the binary that all branches are hidden
- correctly, and allows for flipping and deleting branches to test the test
- cases.
- A major downside is that this requires architecture-specific code. */
- /** @var{a} > @var{b}?
- The fall-through case should be the most likely. */
- __attribute__((always_inline))
- static inline _Bool
- sHT_gt(uintmax_t a, uintmax_t b)
- {
- if (sHT_constant_p(a > b))
- return a > b;
- _sHT_gt(a, b, correct);
- return 0;
- correct:
- return 1;
- }
- /** @var{a} >= @var{b}?
- The fall-through case should be the most likely. */
- __attribute__((always_inline))
- static inline _Bool
- sHT_ge(uintmax_t a, uintmax_t b)
- {
- if (sHT_constant_p(a >= b))
- return a >= b;
- _sHT_ge(a, b, correct);
- return 0;
- correct:
- return 1;
- }
- /** @var{a} == @var{b}?
- The fall-through case should be the most likely. */
- __attribute__((always_inline))
- static inline _Bool
- sHT_eq(uintmax_t a, uintmax_t b)
- {
- if (sHT_constant_p(a == b))
- return a == b;
- _sHT_eq(a, b, correct);
- return 0;
- correct:
- return 1;
- }
- /** @var{a} == @var{b} ? 1 : 0
- This differs from @var{sHT_eq} in that the
- return value is an integer, and not a condition.
- It may not be directly branched upon. */
- __attribute__((always_inline))
- static inline int
- sHT_eq_bool(uintmax_t a, uintmax_t b)
- {
- if (sHT_constant_p(a == b))
- return a == b;
- _Bool ret;
- _sHT_eq_bool(a, b, ret);
- return ret;
- }
- /** @var{a} != @var{b}?
- The fall-through case should be the most likely. */
- static inline _Bool
- sHT_neq(uintmax_t a, uintmax_t b)
- {
- if (sHT_constant_p(a != b))
- return a != b;
- _sHT_neq(a, b, correct);
- return 0;
- correct:
- return 1;
- }
- /** @var{a} < 0? (signed)
- The fall-through case should be the most likely. */
- __attribute__((always_inline))
- static inline _Bool
- sHT_lt0(intmax_t a)
- {
- if (sHT_constant_p(a < 0))
- return a < 0;
- _sHT_lt0(a, correct);
- return 0;
- correct:
- return 1;
- }
- /** @var{a} == 0?
- The fall-through case should be the most likely. */
- __attribute__((always_inline))
- static inline _Bool
- sHT_zero_p(uintmax_t a)
- {
- if (sHT_constant_p(a == 0))
- return a == 0;
- _sHT_zero_p(a, correct);
- return 0;
- correct:
- return 1;
- }
- /** @var{a} != 0?
- The fall-through case should be the most likely. */
- __attribute__((always_inline))
- static inline _Bool
- sHT_nonzero_p(uintmax_t a)
- {
- if (sHT_constant_p(a != 0))
- return a != 0;
- _sHT_nonzero_p(a, correct);
- return 0;
- correct:
- return 1;
- }
- /** @var{a} == @var{b}? Both are pointers.
- The fall-through case should be the most likely. */
- __attribute__((always_inline))
- static inline _Bool
- sHT_eq_pointer(void *a, void *b)
- {
- if (sHT_constant_p(a == b))
- return a == b;
- _sHT_eq(a, b, correct);
- return 0;
- correct:
- return 1;
- }
- /** @var{a} == NULL?
- The fall-through case should be the most likely. */
- __attribute__((always_inline))
- static inline _Bool
- sHT_null_p(void *a)
- {
- if (sHT_constant_p(a == NULL))
- return 1;
- _sHT_zero_p(a, correct);
- return 0;
- correct:
- return 1;
- }
- /** @var{a} & @var{b} != 0?
- The fall-through case should be the most likely. */
- __attribute__((always_inline))
- static inline _Bool
- sHT_and_any(uintmax_t a, uintmax_t b)
- {
- if (sHT_constant_p((a & b) != 0))
- return (a & b) != 0;
- _sHT_and_any_p(a, b, correct);
- return 0;
- correct:
- return 1;
- }
- /** @var{a} & @var{b} == 0?
- The fall-through case should be the most likely. */
- __attribute__((always_inline))
- static inline _Bool
- sHT_and_none(uintmax_t a, uintmax_t b)
- {
- if (sHT_constant_p((a & b) == 0))
- return (a & b) == 0;
- _sHT_and_none_p(a, b, correct);
- return 0;
- correct:
- return 1;
- }
- #endif
|