diff options
author | Robert Hensing <robert@roberthensing.nl> | 2022-01-10 21:17:17 +0100 |
---|---|---|
committer | Robert Hensing <robert@roberthensing.nl> | 2022-01-19 15:21:56 +0100 |
commit | 624f18ad90e3784878e6d303858f59651af68f61 (patch) | |
tree | 0e4e8da37727a496d9ff7977bdba76ddf5ab39f7 | |
parent | 6dd271b7b4a679ce3c2a8d84a39909bb9b60bf9f (diff) |
withBuffer: Make sure to hit the stack protector
-rw-r--r-- | src/libutil/util.hh | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 407505be9..e2192987c 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -671,15 +671,28 @@ template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; std::string showBytes(uint64_t bytes); +/** + `withBuffer(size, fun)` applies `fun` to a temporary `char` array of size `size`. + The array will be allocated either on the stack or on the heap depending on its size +*/ template<typename T = char, typename Fn> -inline auto withBuffer(size_t size, Fn fun) +inline auto withBuffer(size_t n, Fn fun) -> std::invoke_result_t<Fn, T *> { - if (size < 0x10000) { - T buf[size]; + // Large stack allocations can skip past the stack protection page. + const size_t stack_protection_size = 4096; + // We reduce the max stack allocated buffer by an extra amount to increase + // the chance of hitting it, even when `fun`'s first access is some distance + // into its *further* stack frame, particularly if the call was inlined and + // therefore not writing a frame pointer. + const size_t play = 64 * sizeof(char *); // 512B on 64b archs + size_t size_bytes = n * sizeof(T); + + if (size_bytes < stack_protection_size - play) { + T buf[n]; return fun(buf); } else { - auto buf = std::unique_ptr<T[]>(new T[size]); + auto buf = std::unique_ptr<T[]>(new T[n]); return fun(buf.get()); } } |