diff options
author | Robert Hensing <robert@roberthensing.nl> | 2022-01-19 15:20:46 +0100 |
---|---|---|
committer | Robert Hensing <robert@roberthensing.nl> | 2022-01-19 15:21:56 +0100 |
commit | dec774811922d7ee220bb8e2488bc2f7abf61844 (patch) | |
tree | 46d6a4c5f34bcd71302dccfd4604fedc24abb895 /src | |
parent | 624f18ad90e3784878e6d303858f59651af68f61 (diff) |
Replace withBuffer by boost small_vector
Although this will leave gaps in the stack, the performance impact
of those should be insignificant and we get a simpler solution
this way.
Diffstat (limited to 'src')
-rw-r--r-- | src/libstore/derivations.cc | 35 | ||||
-rw-r--r-- | src/libutil/util.hh | 25 |
2 files changed, 22 insertions, 38 deletions
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index f8fe6a59c..5233cfe67 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -4,6 +4,7 @@ #include "util.hh" #include "worker-protocol.hh" #include "fs-accessor.hh" +#include <boost/container/small_vector.hpp> namespace nix { @@ -272,19 +273,27 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi static void printString(string & res, std::string_view s) { - size_t bufSize = s.size() * 2 + 2; - withBuffer(bufSize, [&](char *buf) { - char * p = buf; - *p++ = '"'; - for (auto c : s) - if (c == '\"' || c == '\\') { *p++ = '\\'; *p++ = c; } - else if (c == '\n') { *p++ = '\\'; *p++ = 'n'; } - else if (c == '\r') { *p++ = '\\'; *p++ = 'r'; } - else if (c == '\t') { *p++ = '\\'; *p++ = 't'; } - else *p++ = c; - *p++ = '"'; - res.append(buf, p - buf); - }); + // 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 + + boost::container::small_vector<char, stack_protection_size - play> buffer; + buffer.reserve(s.size() * 2 + 2); + char * buf = buffer.data(); + char * p = buf; + *p++ = '"'; + for (auto c : s) + if (c == '\"' || c == '\\') { *p++ = '\\'; *p++ = c; } + else if (c == '\n') { *p++ = '\\'; *p++ = 'n'; } + else if (c == '\r') { *p++ = '\\'; *p++ = 'r'; } + else if (c == '\t') { *p++ = '\\'; *p++ = 't'; } + else *p++ = c; + *p++ = '"'; + res.append(buf, p - buf); } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index e2192987c..369c44f78 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -671,30 +671,5 @@ 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 n, Fn fun) - -> std::invoke_result_t<Fn, T *> -{ - // 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[n]); - return fun(buf.get()); - } -} } |