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);