From 69e0473f6e98d47c93518424c08ee69ee632c0f0 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 3979048f..0646b10f 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 fc344c0d..5f62f18d 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][approvals]" ) { + 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