From 9b0eb807cd03eb9ba517b8d5371c91d811a7682b Mon Sep 17 00:00:00 2001 From: dxbjavid Date: Mon, 1 Jun 2026 09:33:23 +0530 Subject: [PATCH] Fix out-of-bounds read on trailing backslash in wxRegEx::Replace() wxRegExImpl::Replace() scans replacement.c_str() and does *++p after a backslash. When the replacement ends in a lone backslash, that reads the terminating NUL, the else branch appends it, and the loop's p++ then steps one byte past the NUL so the *p condition reads out of bounds. Keep a trailing backslash verbatim and stop before the increment. Add a test checking that this doesn't result in ASAN errors any more. Closes #26541. --- src/common/regex.cpp | 7 +++++++ tests/regex/wxregextest.cpp | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/common/regex.cpp b/src/common/regex.cpp index 9ca96589a6..6d61bb775e 100644 --- a/src/common/regex.cpp +++ b/src/common/regex.cpp @@ -1158,6 +1158,13 @@ int wxRegExImpl::Replace(wxString *text, index = (size_t)wxStrtoul(p, &end, 10); p = end - 1; // -1 to compensate for p++ in the loop } + else if ( !*p ) + { + // trailing backslash: keep it verbatim and stop here so + // the loop's p++ doesn't read past the terminating NUL + textNew += wxT('\\'); + break; + } //else: backslash used as escape character } else if ( *p == wxT('&') ) diff --git a/tests/regex/wxregextest.cpp b/tests/regex/wxregextest.cpp index fa612d62cb..8907e84999 100644 --- a/tests/regex/wxregextest.cpp +++ b/tests/regex/wxregextest.cpp @@ -161,6 +161,10 @@ TEST_CASE("wxRegEx::Replace", "[regex][replace]") CheckReplace(patn, "123foo456foo", "\\0\\0", "123foo456foo456foo", 1); CheckReplace(patn, "foo123foo123", "bar", "barbar", 2); CheckReplace(patn, "foo123_foo456_foo789", "bar", "bar_bar_bar", 3); + + // A replacement string ending with a lone backslash used to read one byte + // past the end of the buffer; the backslash is now kept verbatim. + CheckReplace(patn, "foo123", "bar\\", "bar\\", 1); } TEST_CASE("wxRegEx::QuoteMeta", "[regex][meta]")