@@ -72,9 +72,14 @@ class TestZeroCopyInputStream final : public ZeroCopyInputStream {
7272 << " The last call was not a successful Next()" ;
7373 ABSL_CHECK_LE (static_cast <size_t >(count), last_returned_buffer_->size ())
7474 << " count must be within bounds of last buffer" ;
75+ // Return the backed up buffer to the front s.t. Next() can return it.
7576 buffers_.push_front (
7677 last_returned_buffer_->substr (last_returned_buffer_->size () - count));
77- last_returned_buffer_ = nullptr ;
78+ // Note that last_returned_buffer_ is moved to last_backed_up_buffer_ to
79+ // avoid use-after-free of data that was exposed to users but not backed up.
80+ // For example, ZCIS::ReadCord() reads data, then backs up unused data
81+ // before copying the data to Cord.
82+ last_backed_up_buffer_ = std::move (last_returned_buffer_);
7883 byte_count_ -= count;
7984 }
8085
@@ -109,6 +114,10 @@ class TestZeroCopyInputStream final : public ZeroCopyInputStream {
109114 // std::optional could work here, but std::unique_ptr makes it more likely
110115 // for sanitizers to detect if the string is used after it is destroyed.
111116 std::unique_ptr<std::string> last_returned_buffer_;
117+ // It is possible that some part of the buffer needs to be valid after the
118+ // unused part is backed up. Keeping last_returned_buffer_ alive broke some
119+ // tests. Instead, we temporarily store it to last_backed_up_buffer_.
120+ std::unique_ptr<std::string> last_backed_up_buffer_;
112121 int64_t byte_count_ = 0 ;
113122};
114123
0 commit comments