From 1fefa989d76202654ba357cfdec1a4eeace945fa Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 13 Feb 2026 22:45:23 +0000 Subject: [PATCH] Rename `RegexMatch` and only include expressions --- java/ql/lib/semmle/code/java/Concepts.qll | 60 ++++--------------- java/ql/lib/semmle/code/java/JDK.qll | 2 +- .../code/java/frameworks/JavaxAnnotations.qll | 2 +- .../lib/semmle/code/java/frameworks/Regex.qll | 4 +- .../code/java/security/PathSanitizer.qll | 4 +- .../semmle/code/java/security/Sanitizers.qll | 10 ++-- 6 files changed, 21 insertions(+), 61 deletions(-) diff --git a/java/ql/lib/semmle/code/java/Concepts.qll b/java/ql/lib/semmle/code/java/Concepts.qll index 327c9a2c459..6ba7c01e3e3 100644 --- a/java/ql/lib/semmle/code/java/Concepts.qll +++ b/java/ql/lib/semmle/code/java/Concepts.qll @@ -7,71 +7,35 @@ overlay[local?] module; import java -private import semmle.code.java.dataflow.DataFlow private import semmle.code.java.frameworks.JavaxAnnotations /** - * A data-flow node that executes a regular expression. + * An expression that represents a regular expression match. * * Extend this class to refine existing API models. If you want to model new APIs, - * extend `RegexExecution::Range` instead. + * extend `RegexMatch::Range` instead. */ -class RegexExecution extends DataFlow::Node instanceof RegexExecution::Range { - /** Gets the data flow node for the regex being executed by this node. */ - DataFlow::Node getRegex() { result = super.getRegex() } +class RegexMatch extends Expr instanceof RegexMatch::Range { + /** Gets the expression for the regex being executed by this node. */ + Expr getRegex() { result = super.getRegex() } - /** Gets a data flow node for the string to be searched or matched against. */ - DataFlow::Node getString() { result = super.getString() } + /** Gets an expression for the string to be searched or matched against. */ + Expr getString() { result = super.getString() } /** - * Gets the name of this regex execution, typically the name of an executing method. + * Gets the name of this regex match, typically the name of an executing method. * This is used for nice alert messages and should include the module if possible. */ string getName() { result = super.getName() } } -/** Provides classes for modeling new regular-expression execution APIs. */ -module RegexExecution { - /** - * A data flow node that executes a regular expression. - * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `RegexExecution` instead. - */ - abstract class Range extends DataFlow::Node { - /** Gets the data flow node for the regex being executed by this node. */ - abstract DataFlow::Node getRegex(); - - /** Gets a data flow node for the string to be searched or matched against. */ - abstract DataFlow::Node getString(); - - /** - * Gets the name of this regex execution, typically the name of an executing method. - * This is used for nice alert messages and should include the module if possible. - */ - abstract string getName(); - } - - private class RangeFromExpr extends Range { - private RegexExecutionExpr::Range ree; - - RangeFromExpr() { this.asExpr() = ree } - - override DataFlow::Node getRegex() { result.asExpr() = ree.getRegex() } - - override DataFlow::Node getString() { result.asExpr() = ree.getString() } - - override string getName() { result = ree.getName() } - } -} - -/** Provides classes for modeling new regular-expression execution APIs. */ -module RegexExecutionExpr { +/** Provides classes for modeling regular-expression execution APIs. */ +module RegexMatch { /** * An expression that executes a regular expression. * * Extend this class to model new APIs. If you want to refine existing API models, - * extend `RegexExecution` instead. + * extend `RegexMatch` instead. */ abstract class Range extends Expr { /** Gets the expression for the regex being executed by this node. */ @@ -81,7 +45,7 @@ module RegexExecutionExpr { abstract Expr getString(); /** - * Gets the name of this regex execution, typically the name of an executing method. + * Gets the name of this regex match, typically the name of an executing method. * This is used for nice alert messages and should include the module if possible. */ abstract string getName(); diff --git a/java/ql/lib/semmle/code/java/JDK.qll b/java/ql/lib/semmle/code/java/JDK.qll index fcb1980a33b..93562c7c3d8 100644 --- a/java/ql/lib/semmle/code/java/JDK.qll +++ b/java/ql/lib/semmle/code/java/JDK.qll @@ -48,7 +48,7 @@ class StringContainsMethod extends Method { } /** A call to the `java.lang.String.matches` method. */ -class StringMatchesCall extends MethodCall, RegexExecutionExpr::Range { +class StringMatchesCall extends MethodCall, RegexMatch::Range { StringMatchesCall() { exists(Method m | m = this.getMethod() | m.getDeclaringType() instanceof TypeString and diff --git a/java/ql/lib/semmle/code/java/frameworks/JavaxAnnotations.qll b/java/ql/lib/semmle/code/java/frameworks/JavaxAnnotations.qll index e1dacb6ed08..b71776ba015 100644 --- a/java/ql/lib/semmle/code/java/frameworks/JavaxAnnotations.qll +++ b/java/ql/lib/semmle/code/java/frameworks/JavaxAnnotations.qll @@ -171,7 +171,7 @@ class WebServiceRefAnnotation extends Annotation { /** * A `@javax.validation.constraints.Pattern` annotation. */ -class PatternAnnotation extends Annotation, RegexExecutionExpr::Range { +class PatternAnnotation extends Annotation, RegexMatch::Range { PatternAnnotation() { this.getType() .hasQualifiedName(["javax.validation.constraints", "jakarta.validation.constraints"], diff --git a/java/ql/lib/semmle/code/java/frameworks/Regex.qll b/java/ql/lib/semmle/code/java/frameworks/Regex.qll index 8e240b09427..2d689da1fcf 100644 --- a/java/ql/lib/semmle/code/java/frameworks/Regex.qll +++ b/java/ql/lib/semmle/code/java/frameworks/Regex.qll @@ -82,7 +82,7 @@ class PatternMatcherCall extends MethodCall { } /** A call to the `matches` method of `java.util.regex.Pattern`. */ -class PatternMatchesCall extends MethodCall, RegexExecutionExpr::Range { +class PatternMatchesCall extends MethodCall, RegexMatch::Range { PatternMatchesCall() { this.getMethod() instanceof PatternMatchesMethod } override Expr getRegex() { result = this.getArgument(0) } @@ -93,7 +93,7 @@ class PatternMatchesCall extends MethodCall, RegexExecutionExpr::Range { } /** A call to the `matches` method of `java.util.regex.Matcher`. */ -class MatcherMatchesCall extends MethodCall, RegexExecutionExpr::Range { +class MatcherMatchesCall extends MethodCall, RegexMatch::Range { MatcherMatchesCall() { this.getMethod() instanceof MatcherMatchesMethod } /** diff --git a/java/ql/lib/semmle/code/java/security/PathSanitizer.qll b/java/ql/lib/semmle/code/java/security/PathSanitizer.qll index ffd50655001..788cd542939 100644 --- a/java/ql/lib/semmle/code/java/security/PathSanitizer.qll +++ b/java/ql/lib/semmle/code/java/security/PathSanitizer.qll @@ -431,9 +431,7 @@ private class ReplaceDirectoryCharactersSanitizer extends StringReplaceOrReplace * Holds if `matchesCall` confirms that `checkedExpr` does not contain any directory characters * on the given `branch`. */ -private predicate isMatchesCall( - RegexExecutionExpr::Range regexMatch, Expr checkedExpr, boolean branch -) { +private predicate isMatchesCall(RegexMatch regexMatch, Expr checkedExpr, boolean branch) { exists(CompileTimeConstantExpr target, string targetValue | target = regexMatch.getRegex() and target.getStringValue() = targetValue and diff --git a/java/ql/lib/semmle/code/java/security/Sanitizers.qll b/java/ql/lib/semmle/code/java/security/Sanitizers.qll index b08d2e43c01..9eb45f3a598 100644 --- a/java/ql/lib/semmle/code/java/security/Sanitizers.qll +++ b/java/ql/lib/semmle/code/java/security/Sanitizers.qll @@ -41,9 +41,9 @@ class SimpleTypeSanitizer extends DataFlow::Node { * make the type recursive. Otherwise use `RegexpCheckBarrier`. */ predicate regexpMatchGuardChecks(Guard guard, Expr e, boolean branch) { - exists(RegexExecutionExpr::Range ree | not ree instanceof Annotation | - guard = ree and - e = ree.getString() + exists(RegexMatch rm | not rm instanceof Annotation | + guard = rm and + e = rm.getString() ) and branch = true } @@ -60,8 +60,6 @@ class RegexpCheckBarrier extends DataFlow::Node { // Annotations don't fit into the model of barrier guards because the // annotation doesn't dominate the sanitized expression, so we instead // treat them as barriers directly. - exists(RegexExecutionExpr::Range ree | ree instanceof Annotation | - this.asExpr() = ree.getString() - ) + exists(RegexMatch rm | rm instanceof Annotation | this.asExpr() = rm.getString()) } }