withBuffer: Make sure to hit the stack protector

This commit is contained in:
Robert Hensing 2022-01-10 21:17:17 +01:00
parent 6dd271b7b4
commit 624f18ad90

View file

@ -671,15 +671,28 @@ template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
std::string showBytes(uint64_t bytes); 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> 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 *> -> std::invoke_result_t<Fn, T *>
{ {
if (size < 0x10000) { // Large stack allocations can skip past the stack protection page.
T buf[size]; 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); return fun(buf);
} else { } else {
auto buf = std::unique_ptr<T[]>(new T[size]); auto buf = std::unique_ptr<T[]>(new T[n]);
return fun(buf.get()); return fun(buf.get());
} }
} }