Skip to content

Commit 21ac431

Browse files
committed
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.
1 parent 0a55749 commit 21ac431

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

AK/BufferedStream.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ class BufferedHelper {
8787
auto const candidate = TRY(find_and_populate_until_any_of(candidates, buffer.size()));
8888

8989
if (stream().is_eof()) {
90-
if (buffer.size() < m_buffer.used_space()) {
90+
if ((candidate.has_value() && candidate->offset + candidate->size > buffer.size())
91+
|| (!candidate.has_value() && buffer.size() < m_buffer.used_space())) {
9192
// Normally, reading from an EOFed stream and receiving bytes
9293
// would mean that the stream is no longer EOF. However, it's
9394
// possible with a buffered stream that the user is able to read

Tests/AK/TestMemoryStream.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* SPDX-License-Identifier: BSD-2-Clause
55
*/
66

7+
#include <AK/BufferedStream.h>
78
#include <AK/MemoryStream.h>
89
#include <AK/String.h>
910
#include <LibTest/TestCase.h>
@@ -270,3 +271,30 @@ TEST_CASE(fixed_memory_read_in_place)
270271
EXPECT_EQ(characters_again, some_words.bytes());
271272
EXPECT(mutable_stream.is_eof());
272273
}
274+
275+
TEST_CASE(buffered_memory_stream_read_line)
276+
{
277+
auto array = Array<u8, 32> {};
278+
279+
// First line: 8 bytes, second line: 24 bytes
280+
array.fill('A');
281+
array[7] = '\n';
282+
array[31] = '\n';
283+
284+
auto memory_stream = make<FixedMemoryStream>(array.span(), FixedMemoryStream::Mode::ReadOnly);
285+
286+
// Buffer for buffered seekable is larger than the stream, so stream goes EOF immediately on read
287+
auto buffered_stream = TRY_OR_FAIL(InputBufferedSeekable<FixedMemoryStream>::create(move(memory_stream), 64));
288+
289+
// Buffer is only 16 bytes, first read succeeds, second fails
290+
auto buffer = TRY_OR_FAIL(ByteBuffer::create_zeroed(16));
291+
292+
auto read_bytes = TRY_OR_FAIL(buffered_stream->read_line(buffer));
293+
294+
EXPECT_EQ(read_bytes, "AAAAAAA"sv);
295+
296+
auto read_or_error = buffered_stream->read_line(buffer);
297+
298+
EXPECT(read_or_error.is_error());
299+
EXPECT_EQ(read_or_error.error().code(), EMSGSIZE);
300+
}

0 commit comments

Comments
 (0)