diff --git a/src/catch2/internal/catch_textflow.cpp b/src/catch2/internal/catch_textflow.cpp index 3979048f37..0646b10f9c 100644 --- a/src/catch2/internal/catch_textflow.cpp +++ b/src/catch2/internal/catch_textflow.cpp @@ -148,8 +148,8 @@ namespace Catch { m_it--; } // Skip back over UTF-8 continuation bytes to the leading byte - while ( isUtf8ContinuationByte( *m_it ) ) { - assert( m_it != m_string->begin() ); + while ( m_it != m_string->begin() && + isUtf8ContinuationByte( *m_it ) ) { m_it--; } } diff --git a/tests/SelfTest/IntrospectiveTests/TextFlow.tests.cpp b/tests/SelfTest/IntrospectiveTests/TextFlow.tests.cpp index fc344c0d4e..b32662f076 100644 --- a/tests/SelfTest/IntrospectiveTests/TextFlow.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/TextFlow.tests.cpp @@ -437,6 +437,25 @@ TEST_CASE( "TextFlow::AnsiSkippingString iterates UTF-8 codepoints", } } +TEST_CASE( "TextFlow::AnsiSkippingString handles invalid UTF-8", + "[TextFlow][ansiskippingstring][regression]" ) { + SECTION( "Continuation byte at the start" ) { + // 0x80 is a continuation byte + AnsiSkippingString str( "\x80" ); + auto it = str.end(); + --it; + CHECK( it == str.begin() ); + CHECK( *it == static_cast( 0x80 ) ); + } + SECTION( "Multiple continuation bytes at the start" ) { + AnsiSkippingString str( "\x80\x80\x80" ); + auto it = str.end(); + --it; + CHECK( it == str.begin() ); + CHECK( *it == static_cast( 0x80 ) ); + } +} + TEST_CASE( "TextFlow::Column wraps UTF-8 text correctly", "[TextFlow][column][approvals]" ) { // "äöü äöü äöü" = 11 codepoints, 17 bytes