C++: Make regex library compile

This commit is contained in:
Jeroen Ketema
2026-07-21 16:10:30 +02:00
committed by GitHub
parent 07449054cc
commit e672fbb849
6 changed files with 28 additions and 45 deletions

View File

@@ -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}

View File

@@ -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() }

View File

@@ -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) }

View File

@@ -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()
}

View File

@@ -1,4 +1,4 @@
import codeql.ruby.Regexp
import semmle.code.cpp.regex.RegexTreeView
query predicate groupName(RegExpGroup g, string name) { name = g.getName() }