From 609f8d0214692a7b0a6dfd84ed470e7194d24823 Mon Sep 17 00:00:00 2001 From: wyu <97944796+wyu71@users.noreply.github.com> Date: Wed, 12 Aug 2026 08:30:00 +0800 Subject: [PATCH] extract-word: also handle EXTRACT_UNESCAPE_RELAX in the escape branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit extract_first_word() handled a backslash followed by another character in the escape-processing branch only when EXTRACT_CUNESCAPE or EXTRACT_UNESCAPE_SEPARATORS was set. With EXTRACT_UNESCAPE_RELAX alone, the backslash was silently dropped and only the following character kept, which is inconsistent with the documented "keep invalid escapes verbatim" intent of RELAX. Let RELAX also enter that branch, so an invalid escape like "\x" is preserved verbatim as "\x" rather than collapsing to "x". EXTRACT_UNESCAPE_RELAX is not used on its own anywhere outside the test cases — the non-test callers always combine it with EXTRACT_CUNESCAPE, which already enters this branch — so only the test cases that use RELAX by itself are affected, and their expectations are updated accordingly. --- src/basic/extract-word.c | 2 +- src/test/test-extract-word.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index 5ebf67437c..c21ac1fde5 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -78,7 +78,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra return -EINVAL; } - if (flags & (EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS)) { + if (flags & (EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS|EXTRACT_UNESCAPE_RELAX)) { bool eight_bit = false; char32_t u; diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c index aad9bbc47d..3e11f5922b 100644 --- a/src/test/test-extract-word.c +++ b/src/test/test-extract-word.c @@ -247,13 +247,13 @@ TEST(extract_first_word) { p = original = "fooo\\ bar quux"; assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0); - ASSERT_STREQ(t, "fooo bar"); + ASSERT_STREQ(t, "fooo\\ bar"); free(t); assert_se(p == original + 10); p = original = "fooo\\ bar quux"; assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0); - ASSERT_STREQ(t, "fooo bar"); + ASSERT_STREQ(t, "fooo\\ bar"); free(t); assert_se(p == original + 10);