From 31ae5fe02130be1ad9b15fac0d61e85970d6baf9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Jul 2026 10:17:31 +0000 Subject: [PATCH] C++: Implement \cX control escapes --- .../code/cpp/regex/internal/ParseRegExp.qll | 5 ++++- cpp/ql/test/library-tests/regex/parse.expected | 15 +++------------ cpp/ql/test/library-tests/regex/regexp.expected | 13 ++++--------- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/regex/internal/ParseRegExp.qll b/cpp/ql/lib/semmle/code/cpp/regex/internal/ParseRegExp.qll index c84091b063f..191d91990da 100644 --- a/cpp/ql/lib/semmle/code/cpp/regex/internal/ParseRegExp.qll +++ b/cpp/ql/lib/semmle/code/cpp/regex/internal/ParseRegExp.qll @@ -344,8 +344,11 @@ abstract class RegExp extends StringLiteral { // wide hex char \uhhhh this.getChar(start + 1) = "u" and end = start + 6 or + // control char \cX + this.getChar(start + 1) = "c" and end = start + 3 + or // escape not handled above; update when adding a new case - not this.getChar(start + 1) in ["x", "u"] and + not this.getChar(start + 1) in ["x", "u", "c"] and not exists(this.getChar(start + 1).toInt()) and end = start + 2 ) diff --git a/cpp/ql/test/library-tests/regex/parse.expected b/cpp/ql/test/library-tests/regex/parse.expected index 0f07ba72809..b2f12c744a0 100644 --- a/cpp/ql/test/library-tests/regex/parse.expected +++ b/cpp/ql/test/library-tests/regex/parse.expected @@ -26,13 +26,9 @@ #-----| [RegExpConstant, RegExpNormalChar] b -#-----| [RegExpConstant, RegExpEscape] \c +#-----| [RegExpConstant, RegExpEscape] \cZ -#-----| [RegExpConstant, RegExpNormalChar] Z - -#-----| [RegExpConstant, RegExpEscape] \c - -#-----| [RegExpConstant, RegExpNormalChar] A +#-----| [RegExpConstant, RegExpEscape] \cA #-----| [RegExpConstant, RegExpEscape] \u{987 @@ -171,10 +167,6 @@ #-----| 1 -> [RegExpConstant, RegExpEscape] \n #-----| 2 -> [RegExpConstant, RegExpNormalChar] b -#-----| [RegExpSequence] \cA -#-----| 0 -> [RegExpConstant, RegExpEscape] \c -#-----| 1 -> [RegExpConstant, RegExpNormalChar] A - #-----| [RegExpSequence] [[:alpha:]][[:digit:]] #-----| 0 -> [RegExpCharacterClass] [[:alpha:]] #-----| 1 -> [RegExpCharacterClass] [[:digit:]] @@ -292,8 +284,7 @@ #-----| 1 -> [RegExpConstant, RegExpNormalChar] 9 #-----| [RegExpCharacterClass] [\cZ] -#-----| 0 -> [RegExpConstant, RegExpEscape] \c -#-----| 1 -> [RegExpConstant, RegExpNormalChar] Z +#-----| 0 -> [RegExpConstant, RegExpEscape] \cZ #-----| [RegExpCharacterClass] [A-F[:digit:]a-f] #-----| 0 -> [RegExpCharacterRange] A-F diff --git a/cpp/ql/test/library-tests/regex/regexp.expected b/cpp/ql/test/library-tests/regex/regexp.expected index 3f3c8b64604..0a5cfb87b6b 100644 --- a/cpp/ql/test/library-tests/regex/regexp.expected +++ b/cpp/ql/test/library-tests/regex/regexp.expected @@ -32,7 +32,6 @@ term | file://:0:0:0:0 | A | RegExpConstant,RegExpNormalChar | | file://:0:0:0:0 | A | RegExpConstant,RegExpNormalChar | | file://:0:0:0:0 | A | RegExpConstant,RegExpNormalChar | -| file://:0:0:0:0 | A | RegExpConstant,RegExpNormalChar | | file://:0:0:0:0 | A-F | RegExpCharacterRange | | file://:0:0:0:0 | A-F | RegExpCharacterRange | | file://:0:0:0:0 | A-F] | RegExpConstant,RegExpNormalChar | @@ -40,7 +39,6 @@ term | file://:0:0:0:0 | F | RegExpConstant,RegExpNormalChar | | file://:0:0:0:0 | F | RegExpConstant,RegExpNormalChar | | file://:0:0:0:0 | Z | RegExpConstant,RegExpNormalChar | -| file://:0:0:0:0 | Z | RegExpConstant,RegExpNormalChar | | file://:0:0:0:0 | [ | RegExpConstant,RegExpNormalChar | | file://:0:0:0:0 | [123] | RegExpCharacterClass | | file://:0:0:0:0 | [A-F[:digit:]a-f] | RegExpCharacterClass | @@ -70,9 +68,8 @@ term | file://:0:0:0:0 | \\] | RegExpConstant,RegExpEscape | | file://:0:0:0:0 | \\b | RegExpSpecialChar | | file://:0:0:0:0 | \\b!a\\B | RegExpSequence | -| file://:0:0:0:0 | \\c | RegExpConstant,RegExpEscape | -| file://:0:0:0:0 | \\c | RegExpConstant,RegExpEscape | -| file://:0:0:0:0 | \\cA | RegExpSequence | +| file://:0:0:0:0 | \\cA | RegExpConstant,RegExpEscape | +| file://:0:0:0:0 | \\cZ | RegExpConstant,RegExpEscape | | file://:0:0:0:0 | \\d | RegExpCharacterClassEscape | | file://:0:0:0:0 | \\d\\D | RegExpSequence | | file://:0:0:0:0 | \\n | RegExpConstant,RegExpEscape | @@ -167,20 +164,18 @@ regExpNormalCharValue | file://:0:0:0:0 | A | A | | file://:0:0:0:0 | A | A | | file://:0:0:0:0 | A | A | -| file://:0:0:0:0 | A | A | | file://:0:0:0:0 | A-F] | A-F] | | file://:0:0:0:0 | F | F | | file://:0:0:0:0 | F | F | | file://:0:0:0:0 | Z | Z | -| file://:0:0:0:0 | Z | Z | | file://:0:0:0:0 | [ | [ | | file://:0:0:0:0 | \\D | D | | file://:0:0:0:0 | \\S | S | | file://:0:0:0:0 | \\W | W | | file://:0:0:0:0 | \\[ | [ | | file://:0:0:0:0 | \\] | ] | -| file://:0:0:0:0 | \\c | c | -| file://:0:0:0:0 | \\c | c | +| file://:0:0:0:0 | \\cA | cA | +| file://:0:0:0:0 | \\cZ | cZ | | file://:0:0:0:0 | \\d | d | | file://:0:0:0:0 | \\n | \n | | file://:0:0:0:0 | \\n | \n |