Fix CordInputStream for huge cord chunks. PiperOrigin-RevId: 952140260
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc index 12a967d..bc48f60 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
@@ -512,9 +512,11 @@ bool CordInputStream::Next(const void** data, int* size) { if (available_ > 0 || NextChunk(0)) { *data = data_ + size_ - available_; - *size = available_; - bytes_remaining_ -= available_; - available_ = 0; + size_t consumed = + std::min(available_, size_t{std::numeric_limits<int>::max()}); + *size = consumed; + bytes_remaining_ -= consumed; + available_ -= consumed; return true; } return false;
diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc index 7a7a022..6a4bc51 100644 --- a/src/google/protobuf/io/zero_copy_stream_unittest.cc +++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc
@@ -844,6 +844,37 @@ EXPECT_EQ(stream.ByteCount(), 10000); } +TEST(CordInputStreamTest, HugeCordNodes) { + if (sizeof(void*) < 8) { + GTEST_SKIP() << "Not enough memory for test."; + } + + std::string input_str; + // We don't care about the bytes, so avoid the cost. + absl::strings_internal::STLStringResizeUninitializedAmortized( + &input_str, + // Something larger than INT_MAX + 3'000'000'000); + absl::Cord source = absl::MakeCordFromExternal(input_str, [](auto) {}); + ASSERT_EQ(source.Chunks().begin()->size(), input_str.size()); + + const char* expected_next = input_str.data(); + size_t size_to_go = input_str.size(); + + CordInputStream stream(&source); + while (size_to_go > 0) { + const void* data; + int size; + ASSERT_TRUE(stream.Next(&data, &size)); + ASSERT_EQ(data, static_cast<const void*>(expected_next)); + ASSERT_GT(size, 0); + ASSERT_LE(size, size_to_go); + + expected_next += size; + size_to_go -= size; + } +} + TEST_F(IoTest, CordIo) { CordOutputStream output; int size = WriteStuff(&output);