Fixes for String{Resize|Append}AndOverwrite
- StringAppendAndOverwrite() should always call StringResizeAndOverwrite()
with at least capacity() in case the standard library decides to shrink
the buffer (Fixes #1965)
- Small refactor to make the minimum growth an addition for clarity and
to make it easier to test 1.5x growth in the future
- Turn an ABSL_HARDENING_ASSERT into a ThrowStdLengthError
- Add a missing std::move
PiperOrigin-RevId: 826107106
Change-Id: I73ee3e98daa10161aa9023b2a879f6178ebedbcf
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 2e64f1a..9dde5e5 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -182,6 +182,7 @@
":resize_and_overwrite",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:throw_delegate",
],
)
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index 24408ca..2b97fb5 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -183,6 +183,7 @@
absl::config
absl::core_headers
absl::strings_resize_and_overwrite
+ absl::throw_delegate
)
absl_cc_test(
diff --git a/absl/strings/internal/append_and_overwrite.h b/absl/strings/internal/append_and_overwrite.h
index 0bb1215..9dec73b 100644
--- a/absl/strings/internal/append_and_overwrite.h
+++ b/absl/strings/internal/append_and_overwrite.h
@@ -16,6 +16,7 @@
#define ABSL_STRINGS_INTERNAL_APPEND_AND_OVERWRITE_H_
#include "absl/base/config.h"
+#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/strings/resize_and_overwrite.h"
@@ -44,17 +45,24 @@
template <typename T, typename Op>
void StringAppendAndOverwrite(T& str, typename T::size_type append_n,
Op append_op) {
- ABSL_HARDENING_ASSERT(str.size() <= str.max_size() - append_n);
+ if (ABSL_PREDICT_FALSE(append_n > str.max_size() - str.size())) {
+ absl::base_internal::ThrowStdLengthError(
+ "absl::strings_internal::StringAppendAndOverwrite");
+ }
+
auto old_size = str.size();
auto resize = old_size + append_n;
- // Make sure to always grow by at least a factor of 2x.
if (resize > str.capacity()) {
- if (ABSL_PREDICT_FALSE(str.capacity() > str.max_size() / 2)) {
+ // Make sure to always grow by at least a factor of 2x.
+ const auto min_growth = str.capacity();
+ if (ABSL_PREDICT_FALSE(str.capacity() > str.max_size() - min_growth)) {
resize = str.max_size();
- } else if (resize < str.capacity() * 2) {
- resize = str.capacity() * 2;
+ } else if (resize < str.capacity() + min_growth) {
+ resize = str.capacity() + min_growth;
}
+ } else {
+ resize = str.capacity();
}
// Avoid calling StringResizeAndOverwrite() here since it does an MSAN
diff --git a/absl/strings/resize_and_overwrite.h b/absl/strings/resize_and_overwrite.h
index 169c685..04c12d2 100644
--- a/absl/strings/resize_and_overwrite.h
+++ b/absl/strings/resize_and_overwrite.h
@@ -159,7 +159,7 @@
} else if constexpr (strings_internal::has_Resize_and_overwrite<T>::value) {
str._Resize_and_overwrite(n, std::move(op));
} else {
- strings_internal::StringResizeAndOverwriteFallback(str, n, op);
+ strings_internal::StringResizeAndOverwriteFallback(str, n, std::move(op));
}
#endif
}