index.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. // SPDX-License-Identifier: GPL-2.0 or GPL-3.0
  2. // Copyright © 2019 Ariadne Devos
  3. // sHT -- operate on indices
  4. #ifndef _sHT_INDEX_H
  5. #define _sHT_INDEX_H
  6. /** Array indices
  7. This module counts from 0 to any number. It eliminates most off-by-one
  8. errors, ensures the index is within bounds on out-of-order architectures
  9. (see Spectre) and results in very clear and terse code.
  10. Academic paper on Spectre: https://spectreattack.com (2018).
  11. Practical news articles on Spectre: https://lwn.net/Kernel/Index (2018-2019).
  12. */
  13. #include <sHT/nospec.h>
  14. #include <sHT/test.h>
  15. #include <stddef.h>
  16. /** Check that the variable @var{i} may be used as an index.
  17. It must be a @var{size_t}. */
  18. #define sHT_index_check(i) \
  19. _Static_assert(_Generic(*&(i), size_t: 1, default: 0), \
  20. "size_t is an appropriate type for indices")
  21. /** Check that the expression @var{n} may be used as an array length.
  22. All unsigned integral types are fine. */
  23. #define sHT_size_check(n) \
  24. _Static_assert(_Generic((n), unsigned: 1, unsigned long: 1, \
  25. unsigned long long: 1, default: 0), \
  26. "size_t is an appropriate type for lengths")
  27. /** Let `i` iterate `{ k | i <= k < n }` in order.
  28. i:
  29. the loop counter, `read ^ write ^ set` (type size_t).
  30. n:
  31. one-past-end value to stop at, a constant integral (unsigned)
  32. Speculatively, stop early or do some extra iterations afterwards
  33. with `0 <= i < n \/ i = 0`. Increment `i` at the end of each iteration.
  34. Lemma: the previous is in the past: at each iteration and after loop,
  35. `∀k, old i <= k < current i` `->` ∃ past iteration with `i = k`
  36. (follows from backwards induction).
  37. This iterator is preferred above a manual for-loop, because comparison
  38. operator is always correct, the index always is within bounds, even
  39. on out-of-order microarchitectures and it can be annotated for formal
  40. analysis.
  41. { braces surrounding sHT_index_continue(...) S; } are required. */
  42. #define sHT_index_continue(i, n) \
  43. /* TODO: on x86, `i < n` is tested twice: when `sHT_index_nospec`
  44. computes the mask, and in the exit condition. Create a specialised
  45. copy. Somewhat tricky because GCC doesn't support asm goto with
  46. output operands. */ \
  47. sHT_index_check((i)); \
  48. sHT_size_check((n)); \
  49. for(; sHT_lt((i), (n)) ? ((i) = sHT_index_nospec((i), (n)), 1) : 0; (i)++)
  50. /** Let `i` iterate `{ k | 0 <= k < n }` in order.
  51. First set `i` to 0, then do `sHT_index_continue(i, n)`.
  52. { braces surrounding sHT_index_iterate(...) S; } are required. */
  53. #define sHT_index_iterate(i, n) \
  54. (i) = 0u; \
  55. sHT_index_continue((i), (n))
  56. #endif