From 64a3ca5fcf00c6bd8ad80ea9551c2dc460e67173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dirk=20M=C3=BCller?= Date: Thu, 7 May 2026 09:39:12 +0200 Subject: [PATCH] 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. --- src/catch2/internal/catch_textflow.cpp | 4 ++-- .../IntrospectiveTests/TextFlow.tests.cpp | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) 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