nemequ / hedley

A C/C++ header to help move #ifdefs out of your code
https://nemequ.github.io/hedley/
Creative Commons Zero v1.0 Universal
774 stars 51 forks source link

Spectre v1 mitigation #17

Open nemequ opened 5 years ago

nemequ commented 5 years ago

GCC 9 has a new builtin, __builtin_speculation_safe_value which I'm quite interested in supporting. It is, of couse, pretty easy to just provide a wrapper around the GCC builtin:

#if defined(HEDLEY_SPECULATION_SAFE_VALUE)
#  undef HEDLEY_SPECULATION_SAFE_VALUE
#endif
#if (HEDLEY_GCC_VERSION_CHECK(9,0,0) && defined(__HAVE_BUILTIN_SPECULATION_SAFE_VALUE))
#  define HEDLEY_SPECULATION_SAFE_VALUE(val, failval) __builtin_speculation_safe_value((val), (failval))
#else
#  define HEDLEY_SPECULATION_SAFE_VALUE(val, failval) (((void) (failval)), (val))
#endif

But I'm a bit worried about portability. I'd hate to choose to implement it this way then have clang and msvc implement something else that is hard to use to provide this API. In particular, I'm wondering if it might be better to just use 0 for failval.

GCC actually allows you to omit failval (in which case it will use 0), and I think most people will probably use it this way. Clang appears to be working to implement a similar builtin, but there is currently a question of whether it will support providing a failval or will just use 0.

There is also unsigned long array_index_mask_nospec(unsigned long index, unsigned long size) from the Linux kernel.

MSVC is a problem, as usual. Since it doesn't support statement expressions I can't think of a way to implement this without emitting code in the header, except probably in C++14 (with a lambda & auto arguments).

Maybe the right solution would be to have two macros, one where you can specify failval and one where 0 is assumed. That way we don't have to worry as much about any additional runtime overhead for a custom failval.

It may also be nice to steal the kernel's OPTIMIZER_HIDE_VAR macro…

Edit: array_index_mask_nospec is looking like the best bet for something portable. Probably preserve that API, and define it to ((size), __builtin_speculation_safe_value(index)) for GCC 9+.

Unfortunately, I'm not sure how to implement it in MSVC; the inline asm trick for OPTIMIZER_HIDE_VAR won't work because 64-bit MSVC doesn't seem to support inline assembly (?!?!?!). If anyone has any ideas please let me know.