Skip to content

Commit 64a3ca5

Browse files
committed
Avoid a potential underflow when iterating over invalid inputs
The forward iteration logic already bounds-check for m_it != m_string->end(), do the same for the backward iteration. The issue with the assert is that the assert() might not be compiled in, and it is happening after the dereference, so it was too late.
1 parent 300c5d3 commit 64a3ca5

2 files changed

Lines changed: 21 additions & 2 deletions

File tree

src/catch2/internal/catch_textflow.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ namespace Catch {
148148
m_it--;
149149
}
150150
// Skip back over UTF-8 continuation bytes to the leading byte
151-
while ( isUtf8ContinuationByte( *m_it ) ) {
152-
assert( m_it != m_string->begin() );
151+
while ( m_it != m_string->begin() &&
152+
isUtf8ContinuationByte( *m_it ) ) {
153153
m_it--;
154154
}
155155
}

tests/SelfTest/IntrospectiveTests/TextFlow.tests.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,25 @@ TEST_CASE( "TextFlow::AnsiSkippingString iterates UTF-8 codepoints",
437437
}
438438
}
439439

440+
TEST_CASE( "TextFlow::AnsiSkippingString handles invalid UTF-8",
441+
"[TextFlow][ansiskippingstring][regression]" ) {
442+
SECTION( "Continuation byte at the start" ) {
443+
// 0x80 is a continuation byte
444+
AnsiSkippingString str( "\x80" );
445+
auto it = str.end();
446+
--it;
447+
CHECK( it == str.begin() );
448+
CHECK( *it == static_cast<char>( 0x80 ) );
449+
}
450+
SECTION( "Multiple continuation bytes at the start" ) {
451+
AnsiSkippingString str( "\x80\x80\x80" );
452+
auto it = str.end();
453+
--it;
454+
CHECK( it == str.begin() );
455+
CHECK( *it == static_cast<char>( 0x80 ) );
456+
}
457+
}
458+
440459
TEST_CASE( "TextFlow::Column wraps UTF-8 text correctly",
441460
"[TextFlow][column][approvals]" ) {
442461
// "äöü äöü äöü" = 11 codepoints, 17 bytes

0 commit comments

Comments
 (0)