AK: Allow reading from EOF buffered streams better in read_line()

If the BufferedStream is able to fill its entire circular buffer in
populate_read_buffer() and is later asked to read a line or read until
a delimiter, it could erroneously return EMSGSIZE if the caller's buffer
was smaller than the internal buffer. In this case, all we really care
about is whether the caller's buffer is big enough for however much data
we're going to copy into it. Which needs to take into account the
candidate.
This commit is contained in:
Andrew Kaster 2024-02-21 19:42:27 -07:00 committed by Andrew Kaster
parent 0a55749a39
commit 21ac431fac
Notes: sideshowbarker 2024-07-17 02:55:44 +09:00
2 changed files with 30 additions and 1 deletions

View file

@ -87,7 +87,8 @@ public:
auto const candidate = TRY(find_and_populate_until_any_of(candidates, buffer.size()));
if (stream().is_eof()) {
if (buffer.size() < m_buffer.used_space()) {
if ((candidate.has_value() && candidate->offset + candidate->size > buffer.size())
|| (!candidate.has_value() && buffer.size() < m_buffer.used_space())) {
// Normally, reading from an EOFed stream and receiving bytes
// would mean that the stream is no longer EOF. However, it's
// possible with a buffered stream that the user is able to read

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/BufferedStream.h>
#include <AK/MemoryStream.h>
#include <AK/String.h>
#include <LibTest/TestCase.h>
@ -270,3 +271,30 @@ TEST_CASE(fixed_memory_read_in_place)
EXPECT_EQ(characters_again, some_words.bytes());
EXPECT(mutable_stream.is_eof());
}
TEST_CASE(buffered_memory_stream_read_line)
{
auto array = Array<u8, 32> {};
// First line: 8 bytes, second line: 24 bytes
array.fill('A');
array[7] = '\n';
array[31] = '\n';
auto memory_stream = make<FixedMemoryStream>(array.span(), FixedMemoryStream::Mode::ReadOnly);
// Buffer for buffered seekable is larger than the stream, so stream goes EOF immediately on read
auto buffered_stream = TRY_OR_FAIL(InputBufferedSeekable<FixedMemoryStream>::create(move(memory_stream), 64));
// Buffer is only 16 bytes, first read succeeds, second fails
auto buffer = TRY_OR_FAIL(ByteBuffer::create_zeroed(16));
auto read_bytes = TRY_OR_FAIL(buffered_stream->read_line(buffer));
EXPECT_EQ(read_bytes, "AAAAAAA"sv);
auto read_or_error = buffered_stream->read_line(buffer);
EXPECT(read_or_error.is_error());
EXPECT_EQ(read_or_error.error().code(), EMSGSIZE);
}