In `StringWriter`, fix poisoning of memory supposed to be unused. After seeking
back, it is possible that `written_size_` exceeds the cursor, in which case
memory between the cursor and `written_size_` is valid and must not be poisoned.
In `{String,Resizable}Writer::Push()`, protect against the theoretical
possibility of `recommended_length` being so large that it overflows `size_t`
when added to `size()`.
Optimize a call to `std::string::reserve()`: since C++20 it can no longer be
interpreted as a non-binding shrink request.
Clean up comments at `ResizableWriter`.
PiperOrigin-RevId: 868698749
diff --git a/riegeli/bytes/resizable_writer.cc b/riegeli/bytes/resizable_writer.cc
index beb3b8f..b7abe97 100644
--- a/riegeli/bytes/resizable_writer.cc
+++ b/riegeli/bytes/resizable_writer.cc
@@ -93,8 +93,8 @@
// data are written than space requested.
//
// Resize the destination also if data follow the current position.
- return GrowDestAndMakeBuffer(IntCast<size_t>(pos()) +
- UnsignedMax(min_length, recommended_length));
+ return GrowDestAndMakeBuffer(SaturatingAdd(
+ IntCast<size_t>(pos()), UnsignedMax(min_length, recommended_length)));
}
GrowDestToCapacityAndMakeBuffer();
if (min_length <= available()) return true;
diff --git a/riegeli/bytes/resizable_writer.h b/riegeli/bytes/resizable_writer.h
index bec6c92..070a957 100644
--- a/riegeli/bytes/resizable_writer.h
+++ b/riegeli/bytes/resizable_writer.h
@@ -211,9 +211,10 @@
// // itself is being moved.
// static constexpr bool kIsStable;
//
-// // Sets the size of `dest` to `new_size`. The prefix of data with
-// // `used_size` is preserved. Remaining space is unspecified. Returns
-// // `true` on success, or `false` on failure.
+// // Sets the size of `dest` to `new_size`.
+// //
+// // The prefix of data with `used_size` is preserved. Remaining space is
+// // unspecified. Returns `true` on success, or `false` on failure.
// //
// // The intent is to resize exactly to `new_size`, but the size reported by
// // `Size(dest)` can be larger than `new_size` if `dest` cannot represent
@@ -230,9 +231,11 @@
//
// // Increases the size of `dest` at least to `new_size`, or more to ensure
// // amortized constant time of reallocation, or more if this can be done
-// // without allocating more. Does not decrease the size of `dest`.
+// // without allocating more. Does not decrease the size of `dest` even if
+// // `new_size < Size(dest)`.
+// //
// // The prefix of data with `used_size` is preserved. Remaining space is
-// // unspecified. Returns the `true` on success, or `false` on failure.
+// // unspecified. Returns `true` on success, or `false` on failure.
// //
// // Preconditions:
// // `used_size <= Size(dest)`
diff --git a/riegeli/bytes/string_writer.cc b/riegeli/bytes/string_writer.cc
index b06bef5..44d648a 100644
--- a/riegeli/bytes/string_writer.cc
+++ b/riegeli/bytes/string_writer.cc
@@ -77,7 +77,7 @@
"secondary buffer is used";
dest.resize(dest.capacity());
MakeDestBuffer(dest, cursor_index);
- MarkPoisoned(cursor(), available());
+ MarkPoisoned(start() + used_size(), start_to_limit() - used_size());
}
inline void StringWriterBase::SyncSecondaryBuffer() {
@@ -136,9 +136,15 @@
// are written than space requested.
//
// Resize `dest` also if data follow the current position.
- const size_t size_hint =
- cursor_index + UnsignedMax(min_length, recommended_length);
+ const size_t size_hint = SaturatingAdd(
+ cursor_index, UnsignedMax(min_length, recommended_length));
+ // Before C++20, `std::string::reserve()` with a reduced capacity is a
+ // non-binding shrink request. Since C++20, it has no effect.
+#if __cplusplus >= 202002
+ dest.reserve(size_hint);
+#else
if (dest.capacity() < size_hint) dest.reserve(size_hint);
+#endif
}
if (min_length <= dest.capacity() - cursor_index) {
GrowDestToCapacityAndMakeBuffer(dest, cursor_index);