From 995c4f306890ad379de19106f053238ce89f1483 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 7 Feb 2022 11:33:08 -0800 Subject: [PATCH] [demangler] Fix buffer growth The output buffer growth algorithm had a few issues: a) An off-by-one error in the initial size check, which uses '>='. This error was safe, but could cause us to reallocate when there was no need. b) An inconsistency between the initial size check (>=) and the post-doubling check (>). The latter was somewhat obscured by the swapped operands. c) There would be many reallocs with an initially-small buffer. Add a little initialization hysteresis. Reviewed By: ChuanqiXu Differential Revision: https://reviews.llvm.org/D119177 --- libcxxabi/src/demangle/Utility.h | 12 +++++++----- llvm/include/llvm/Demangle/Utility.h | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/libcxxabi/src/demangle/Utility.h b/libcxxabi/src/demangle/Utility.h index 93ef2aa..97272ae 100644 --- a/libcxxabi/src/demangle/Utility.h +++ b/libcxxabi/src/demangle/Utility.h @@ -33,12 +33,14 @@ class OutputBuffer { size_t CurrentPosition = 0; size_t BufferCapacity = 0; - // Ensure there is at least n more positions in buffer. + // Ensure there are at least N more positions in the buffer. void grow(size_t N) { - if (N + CurrentPosition >= BufferCapacity) { - BufferCapacity *= 2; - if (BufferCapacity < N + CurrentPosition) - BufferCapacity = N + CurrentPosition; + size_t Need = N + CurrentPosition; + if (Need > BufferCapacity) { + // Avoid many reallocations during startup, with a bit of hysteresis. + constexpr size_t MinInitAlloc = 1024; + Need = std::max(Need, MinInitAlloc); + BufferCapacity = std::max(Need, BufferCapacity * 2); Buffer = static_cast(std::realloc(Buffer, BufferCapacity)); if (Buffer == nullptr) std::terminate(); diff --git a/llvm/include/llvm/Demangle/Utility.h b/llvm/include/llvm/Demangle/Utility.h index 58b1954e..df520f5 100644 --- a/llvm/include/llvm/Demangle/Utility.h +++ b/llvm/include/llvm/Demangle/Utility.h @@ -33,12 +33,14 @@ class OutputBuffer { size_t CurrentPosition = 0; size_t BufferCapacity = 0; - // Ensure there is at least n more positions in buffer. + // Ensure there are at least N more positions in the buffer. void grow(size_t N) { - if (N + CurrentPosition >= BufferCapacity) { - BufferCapacity *= 2; - if (BufferCapacity < N + CurrentPosition) - BufferCapacity = N + CurrentPosition; + size_t Need = N + CurrentPosition; + if (Need > BufferCapacity) { + // Avoid many reallocations during startup, with a bit of hysteresis. + constexpr size_t MinInitAlloc = 1024; + Need = std::max(Need, MinInitAlloc); + BufferCapacity = std::max(Need, BufferCapacity * 2); Buffer = static_cast(std::realloc(Buffer, BufferCapacity)); if (Buffer == nullptr) std::terminate(); -- 2.7.4