test.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. // Copyright © 2018-2019 Ariadne Devos
  3. /* sHT -- compare values, on a Spectre-oblivious compiler */
  4. #ifndef _sHT_TEST_H
  5. #define _sHT_TEST_H
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <sHT/compiler.h>
  9. #include <sHT/test-arch.h>
  10. /** Comparing values
  11. If two values are compared, the compiler can assume information in both
  12. branches, which may be -- speculatively -- incorrect. s2 must not allow
  13. side-channel attacks.
  14. Why use inline assembly instead of littering the code with
  15. @var{sHT_hide_var}? Because its a lie that the variable changes,
  16. reducing optimisation opportunities, because its fragile: information
  17. about a parameter implies information about other data, because it is
  18. less verbose, and because branches can easily be marked.
  19. The last allows for checking the binary that all branches are hidden
  20. correctly, and allows for flipping and deleting branches to test the test
  21. cases.
  22. A major downside is that this requires architecture-specific code. */
  23. /** @var{a} > @var{b}?
  24. The fall-through case should be the most likely. */
  25. __attribute__((always_inline))
  26. static inline _Bool
  27. sHT_gt(uintmax_t a, uintmax_t b)
  28. {
  29. if (sHT_constant_p(a > b))
  30. return a > b;
  31. _sHT_gt(a, b, correct);
  32. return 0;
  33. correct:
  34. return 1;
  35. }
  36. /** @var{a} >= @var{b}?
  37. The fall-through case should be the most likely. */
  38. __attribute__((always_inline))
  39. static inline _Bool
  40. sHT_ge(uintmax_t a, uintmax_t b)
  41. {
  42. if (sHT_constant_p(a >= b))
  43. return a >= b;
  44. _sHT_ge(a, b, correct);
  45. return 0;
  46. correct:
  47. return 1;
  48. }
  49. /** @var{a} == @var{b}?
  50. The fall-through case should be the most likely. */
  51. __attribute__((always_inline))
  52. static inline _Bool
  53. sHT_eq(uintmax_t a, uintmax_t b)
  54. {
  55. if (sHT_constant_p(a == b))
  56. return a == b;
  57. _sHT_eq(a, b, correct);
  58. return 0;
  59. correct:
  60. return 1;
  61. }
  62. /** @var{a} == @var{b} ? 1 : 0
  63. This differs from @var{sHT_eq} in that the
  64. return value is an integer, and not a condition.
  65. It may not be directly branched upon. */
  66. __attribute__((always_inline))
  67. static inline int
  68. sHT_eq_bool(uintmax_t a, uintmax_t b)
  69. {
  70. if (sHT_constant_p(a == b))
  71. return a == b;
  72. _Bool ret;
  73. _sHT_eq_bool(a, b, ret);
  74. return ret;
  75. }
  76. /** @var{a} != @var{b}?
  77. The fall-through case should be the most likely. */
  78. static inline _Bool
  79. sHT_neq(uintmax_t a, uintmax_t b)
  80. {
  81. if (sHT_constant_p(a != b))
  82. return a != b;
  83. _sHT_neq(a, b, correct);
  84. return 0;
  85. correct:
  86. return 1;
  87. }
  88. /** @var{a} < 0? (signed)
  89. The fall-through case should be the most likely. */
  90. __attribute__((always_inline))
  91. static inline _Bool
  92. sHT_lt0(intmax_t a)
  93. {
  94. if (sHT_constant_p(a < 0))
  95. return a < 0;
  96. _sHT_lt0(a, correct);
  97. return 0;
  98. correct:
  99. return 1;
  100. }
  101. /** @var{a} == 0?
  102. The fall-through case should be the most likely. */
  103. __attribute__((always_inline))
  104. static inline _Bool
  105. sHT_zero_p(uintmax_t a)
  106. {
  107. if (sHT_constant_p(a == 0))
  108. return a == 0;
  109. _sHT_zero_p(a, correct);
  110. return 0;
  111. correct:
  112. return 1;
  113. }
  114. /** @var{a} != 0?
  115. The fall-through case should be the most likely. */
  116. __attribute__((always_inline))
  117. static inline _Bool
  118. sHT_nonzero_p(uintmax_t a)
  119. {
  120. if (sHT_constant_p(a != 0))
  121. return a != 0;
  122. _sHT_nonzero_p(a, correct);
  123. return 0;
  124. correct:
  125. return 1;
  126. }
  127. /** @var{a} == @var{b}? Both are pointers.
  128. The fall-through case should be the most likely. */
  129. __attribute__((always_inline))
  130. static inline _Bool
  131. sHT_eq_pointer(void *a, void *b)
  132. {
  133. if (sHT_constant_p(a == b))
  134. return a == b;
  135. _sHT_eq(a, b, correct);
  136. return 0;
  137. correct:
  138. return 1;
  139. }
  140. /** @var{a} == NULL?
  141. The fall-through case should be the most likely. */
  142. __attribute__((always_inline))
  143. static inline _Bool
  144. sHT_null_p(void *a)
  145. {
  146. if (sHT_constant_p(a == NULL))
  147. return 1;
  148. _sHT_zero_p(a, correct);
  149. return 0;
  150. correct:
  151. return 1;
  152. }
  153. /** @var{a} & @var{b} != 0?
  154. The fall-through case should be the most likely. */
  155. __attribute__((always_inline))
  156. static inline _Bool
  157. sHT_and_any(uintmax_t a, uintmax_t b)
  158. {
  159. if (sHT_constant_p((a & b) != 0))
  160. return (a & b) != 0;
  161. _sHT_and_any_p(a, b, correct);
  162. return 0;
  163. correct:
  164. return 1;
  165. }
  166. /** @var{a} & @var{b} == 0?
  167. The fall-through case should be the most likely. */
  168. __attribute__((always_inline))
  169. static inline _Bool
  170. sHT_and_none(uintmax_t a, uintmax_t b)
  171. {
  172. if (sHT_constant_p((a & b) == 0))
  173. return (a & b) == 0;
  174. _sHT_and_none_p(a, b, correct);
  175. return 0;
  176. correct:
  177. return 1;
  178. }
  179. #endif