From e672fbb84904e3360fd182d246bf639c24ef7ba8 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 21 Jul 2026 16:10:30 +0200 Subject: [PATCH] C++: Make regex library compile --- cpp/ql/lib/qlpack.yml | 1 + .../semmle/code/cpp/regex/RegexTreeView.qll | 44 +++++++------------ .../code/cpp/regex/internal/ParseRegExp.qll | 17 +++---- cpp/ql/test/library-tests/regex/parse.ql | 9 ++-- .../regex/{regexp.rb => regexp.cpp} | 0 cpp/ql/test/library-tests/regex/regexp.ql | 2 +- 6 files changed, 28 insertions(+), 45 deletions(-) rename cpp/ql/test/library-tests/regex/{regexp.rb => regexp.cpp} (100%) diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 5f4b92a191f..775e8c71729 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -10,6 +10,7 @@ dependencies: codeql/mad: ${workspace} codeql/quantum: ${workspace} codeql/rangeanalysis: ${workspace} + codeql/regex: ${workspace} codeql/ssa: ${workspace} codeql/typeflow: ${workspace} codeql/tutorial: ${workspace} diff --git a/cpp/ql/lib/semmle/code/cpp/regex/RegexTreeView.qll b/cpp/ql/lib/semmle/code/cpp/regex/RegexTreeView.qll index 51df1700881..a0a116f2fe0 100644 --- a/cpp/ql/lib/semmle/code/cpp/regex/RegexTreeView.qll +++ b/cpp/ql/lib/semmle/code/cpp/regex/RegexTreeView.qll @@ -1,17 +1,17 @@ -/** Provides a class hierarchy corresponding to a parse tree of regular expressions. */ +/** + * Provides a class hierarchy corresponding to a parse tree of C++ regular expressions. + */ private import internal.ParseRegExp private import codeql.util.Numbers -private import codeql.ruby.ast.Literal as Ast -private import codeql.Locations -private import codeql.regex.nfa.NfaUtils as NfaUtils +private import semmle.code.cpp.exprs.Literal private import codeql.regex.RegexTreeView // exporting as RegexTreeView, and in the top-level scope. import Impl as RegexTreeView import Impl /** Gets the parse tree resulting from parsing `re`, if such has been constructed. */ -RegExpTerm getParsedRegExp(Ast::RegExpLiteral re) { +RegExpTerm getParsedRegExp(StringLiteral re) { result.getRegExp() = re and result.isRootTerm() } @@ -55,7 +55,7 @@ private newtype TRegExpParent = re.namedCharacterProperty(start, end, _) } -/** An implementation that statisfies the RegexTreeView signature. */ +/** An implementation that satisfies the RegexTreeView signature. */ private module Impl implements RegexTreeViewSig { /** * An element containing a regular expression term, that is, either @@ -211,24 +211,14 @@ private module Impl implements RegexTreeViewSig { */ Location getLocation() { result = re.getLocation() } - pragma[noinline] - private predicate componentHasLocationInfo( - int i, string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - re.getComponent(i) - .getLocation() - .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - /** Holds if this term is found at the specified location offsets. */ predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { exists(int re_start | - this.componentHasLocationInfo(0, filepath, startline, re_start, _, _) and - this.componentHasLocationInfo(re.getNumberOfComponents() - 1, filepath, _, _, endline, _) and - startcolumn = re_start + start and - endcolumn = re_start + end - 1 + re.getLocation().hasLocationInfo(filepath, startline, re_start, endline, _) and + startcolumn = re_start + 1 + start and + endcolumn = re_start + 1 + end - 1 ) } @@ -312,7 +302,7 @@ private module Impl implements RegexTreeViewSig { result.getEnd() = part_end } - /** Hols if this term may match an unlimited number of times. */ + /** Hodls if this term may match an unlimited number of times. */ predicate mayRepeatForever() { may_repeat_forever = true } /** Gets the qualifier for this term. That is e.g "?" for "a?". */ @@ -660,9 +650,9 @@ private module Impl implements RegexTreeViewSig { * * Examples: * - * ```rb - * /[a-fA-F0-9]/ - * /[^abc]/ + * ```cpp + * "[a-fA-F0-9]" + * "[^abc]" * ``` */ class RegExpCharacterClass extends RegExpTerm, TRegExpCharacterClass { @@ -1195,9 +1185,7 @@ private module Impl implements RegexTreeViewSig { /** * Holds if the regular expression should not be considered. */ - predicate isExcluded(RegExpParent parent) { - parent.(RegExpTerm).getRegExp().(Ast::RegExpLiteral).hasFreeSpacingFlag() // exclude free-spacing mode regexes - } + predicate isExcluded(RegExpParent parent) { none() } /** * Holds if `term` is a possessive quantifier. @@ -1207,13 +1195,13 @@ private module Impl implements RegexTreeViewSig { /** * Holds if the regex that `term` is part of is used in a way that ignores any leading prefix of the input it's matched against. - * Not yet implemented for Ruby. + * Not yet implemented for C++. */ predicate matchesAnyPrefix(RegExpTerm term) { any() } /** * Holds if the regex that `term` is part of is used in a way that ignores any trailing suffix of the input it's matched against. - * Not yet implemented for Ruby. + * Not yet implemented for C++. */ predicate matchesAnySuffix(RegExpTerm term) { any() } 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 d35d9353bf1..d9163bb3af0 100644 --- a/cpp/ql/lib/semmle/code/cpp/regex/internal/ParseRegExp.qll +++ b/cpp/ql/lib/semmle/code/cpp/regex/internal/ParseRegExp.qll @@ -1,19 +1,18 @@ /** - * Library for parsing for Ruby regular expressions. + * Library for parsing for C++ regular expressions. * * N.B. does not yet handle stripping whitespace and comments in regexes with * the `x` (free-spacing) flag. */ -private import codeql.ruby.AST as Ast -private import codeql.Locations +private import semmle.code.cpp.exprs.Literal /** - * A `StringlikeLiteral` containing a regular expression term, that is, either + * A C++ string literal containing a regular expression term, that is, either * a regular expression literal, or a string literal used in a context where - * it is parsed as regular expression. + * it is parsed as a regular expression. */ -abstract class RegExp extends Ast::StringlikeLiteral { +abstract class RegExp extends StringLiteral { /** * Holds if this `RegExp` has the `s` flag for multi-line matching. */ @@ -254,11 +253,7 @@ abstract class RegExp extends Ast::StringlikeLiteral { } /** Gets the text of this regex */ - string getText() { - exists(Ast::ConstantValue c | c = this.getConstantValue() | - result = [this.getConstantValue().getString(), this.getConstantValue().getRegExp()] - ) - } + string getText() { result = this.getValue() } /** Gets the `i`th character of this regex */ string getChar(int i) { result = this.getText().charAt(i) } diff --git a/cpp/ql/test/library-tests/regex/parse.ql b/cpp/ql/test/library-tests/regex/parse.ql index 9bc804ada4d..ba9a04ab9bd 100644 --- a/cpp/ql/test/library-tests/regex/parse.ql +++ b/cpp/ql/test/library-tests/regex/parse.ql @@ -2,10 +2,9 @@ * @kind graph */ -import codeql.Locations -import codeql.ruby.Regexp as RE +import semmle.code.cpp.regex.RegexTreeView -query predicate nodes(RE::RegExpTerm n, string attr, string val) { +query predicate nodes(RegExpTerm n, string attr, string val) { attr = "semmle.label" and val = "[" + concat(n.getAPrimaryQlClass(), ", ") + "] " + n.toString() or @@ -13,7 +12,7 @@ query predicate nodes(RE::RegExpTerm n, string attr, string val) { val = any(int i | n = - rank[i](RE::RegExpTerm t, string fp, int sl, int sc, int el, int ec | + rank[i](RegExpTerm t, string fp, int sl, int sc, int el, int ec | t.hasLocationInfo(fp, sl, sc, el, ec) | t order by fp, sl, sc, el, ec, t.toString() @@ -21,7 +20,7 @@ query predicate nodes(RE::RegExpTerm n, string attr, string val) { ).toString() } -query predicate edges(RE::RegExpTerm pred, RE::RegExpTerm succ, string attr, string val) { +query predicate edges(RegExpTerm pred, RegExpTerm succ, string attr, string val) { attr in ["semmle.label", "semmle.order"] and val = any(int i | succ = pred.getChild(i)).toString() } diff --git a/cpp/ql/test/library-tests/regex/regexp.rb b/cpp/ql/test/library-tests/regex/regexp.cpp similarity index 100% rename from cpp/ql/test/library-tests/regex/regexp.rb rename to cpp/ql/test/library-tests/regex/regexp.cpp diff --git a/cpp/ql/test/library-tests/regex/regexp.ql b/cpp/ql/test/library-tests/regex/regexp.ql index 90fd09ab1be..e167cb1a7bb 100644 --- a/cpp/ql/test/library-tests/regex/regexp.ql +++ b/cpp/ql/test/library-tests/regex/regexp.ql @@ -1,4 +1,4 @@ -import codeql.ruby.Regexp +import semmle.code.cpp.regex.RegexTreeView query predicate groupName(RegExpGroup g, string name) { name = g.getName() }