AK+Test: Fix a logic error in CircularBuffer::offset_of()

This error was introduced by 9a7accdd and had a significant impact on
`BufferedFile` behavior. Hence, we started seeing crash in test262.

By itself, the issue was a wrong calculation of the internal reading
spans when using the `read` and `until` parameters. Which can lead to
at worse crash in VERIFY and at least weird behaviors as missed needles
or detections out of bounds.

It was also accompanied by an erroneous test.

This patch fixes the bug, the test and also provides more tests.
This commit is contained in:
Lucas CHOLLET 2023-01-15 17:14:11 -05:00 committed by Linus Groh
parent c5daa6d997
commit 3b824ec8c9
Notes: sideshowbarker 2024-07-18 03:20:18 +09:00
2 changed files with 39 additions and 4 deletions

View file

@ -60,15 +60,15 @@ Optional<size_t> CircularBuffer::offset_of(StringView needle, Optional<size_t> f
Array<ReadonlyBytes, 2> spans {};
spans[0] = next_read_span();
auto const original_span_0_size = spans[0].size();
if (read_from > 0)
spans[0] = spans[0].slice(min(spans[0].size(), read_from));
if (spans[0].size() + read_from > read_until)
spans[0] = spans[0].trim(read_until - read_from);
if (is_wrapping_around())
spans[1] = m_buffer.span().slice(max(spans[0].size(), read_from) - spans[0].size(), min(read_until, m_used_space) - spans[0].size());
else if (is_wrapping_around())
spans[1] = m_buffer.span().slice(max(original_span_0_size, read_from) - original_span_0_size, min(read_until, m_used_space) - original_span_0_size);
auto maybe_found = AK::memmem(spans.begin(), spans.end(), needle.bytes());
if (maybe_found.has_value())

View file

@ -310,6 +310,41 @@ TEST_CASE(offset_of_with_until_and_after)
result = circular_buffer.offset_of("o Frie"sv, 4, 10);
EXPECT_EQ(result.value_or(42), 4ul);
result = circular_buffer.offset_of("el"sv, 3, 14);
result = circular_buffer.offset_of("el"sv, 3, 17);
EXPECT_EQ(result.value_or(42), 15ul);
}
TEST_CASE(offset_of_with_until_and_after_wrapping_around)
{
auto const source = "Well Hello Friends!"sv;
auto byte_buffer_or_error = ByteBuffer::copy(source.bytes());
EXPECT(!byte_buffer_or_error.is_error());
auto byte_buffer = byte_buffer_or_error.release_value();
auto circular_buffer_or_error = CircularBuffer::create_empty(19);
EXPECT(!circular_buffer_or_error.is_error());
auto circular_buffer = circular_buffer_or_error.release_value();
auto written_bytes = circular_buffer.write(byte_buffer.span().trim(5));
EXPECT_EQ(written_bytes, 5ul);
auto result = circular_buffer.offset_of("Well "sv, 0, 5);
EXPECT_EQ(result.value_or(42), 0ul);
written_bytes = circular_buffer.write(byte_buffer.span().slice(5));
EXPECT_EQ(written_bytes, 14ul);
result = circular_buffer.offset_of("Hello Friends!"sv, 5, 19);
EXPECT_EQ(result.value_or(42), 5ul);
safe_discard(circular_buffer, 5);
result = circular_buffer.offset_of("Hello Friends!"sv, 0, 14);
EXPECT_EQ(result.value_or(42), 0ul);
written_bytes = circular_buffer.write(byte_buffer.span().trim(5));
EXPECT_EQ(written_bytes, 5ul);
result = circular_buffer.offset_of("Well "sv, 14, 19);
EXPECT_EQ(result.value_or(42), 14ul);
}