@@ -37,31 +37,57 @@ class SimpleTypeSanitizer extends DataFlow::Node {
3737 *
3838 * This is overapproximate: we do not attempt to reason about the correctness of the regexp.
3939 *
40- * Use this if you want to define a derived `DataFlow::BarrierGuard` without
41- * make the type recursive. Otherwise use `RegexpCheckBarrier`.
40+ * This holds for both method-call and annotation regular-expression matches.
41+ * Used directly with `DataFlow::BarrierGuard`, only method-call matches yield
42+ * barrier nodes, since an annotation does not dominate the expression it
43+ * constrains. Use `RegexMatchBarrier` (as `RegexpCheckBarrier` does) to also
44+ * treat annotation matches as barriers.
4245 */
4346predicate regexpMatchGuardChecks ( Guard guard , Expr e , boolean branch ) {
44- exists ( RegexMatch rm | not rm instanceof Annotation |
47+ exists ( RegexMatch rm |
4548 guard = rm and
4649 e = rm .getASanitizedExpr ( ) and
4750 branch = true
4851 )
4952}
5053
54+ /** A guard-check predicate over regular-expression matches, as used by `RegexMatchBarrier`. */
55+ signature predicate regexMatchGuardChecksSig ( Guard g , Expr e , boolean branch ) ;
56+
57+ /**
58+ * Given a guard-check predicate that includes regular-expression matches,
59+ * this module provides the corresponding barrier nodes, transparently handling
60+ * the two kinds of `RegexMatch`:
61+ * - method calls, which act as ordinary control-flow barrier guards, and
62+ * - annotations, which don't dominate the expressions they constrain and so
63+ * are instead treated as direct barriers.
64+ *
65+ * Callers do not need to distinguish between the two: include annotation
66+ * matches in `guardChecks` (with `branch = true`, since an annotation is
67+ * always present) and use `getABarrierNode` in place of a direct
68+ * `DataFlow::BarrierGuard` instantiation.
69+ */
70+ module RegexMatchBarrier< regexMatchGuardChecksSig / 3 guardChecks> {
71+ /** Gets a node that is sanitized by a regular-expression match. */
72+ DataFlow:: Node getABarrierNode ( ) {
73+ result = DataFlow:: BarrierGuard< guardChecks / 3 > :: getABarrierNode ( )
74+ or
75+ // An annotation doesn't dominate the expression it constrains, so the
76+ // barrier-guard machinery above never yields a node for it; treat it as a
77+ // direct barrier instead.
78+ exists ( Guard g , Expr e |
79+ g instanceof Annotation and guardChecks ( g , e , true ) and result .asExpr ( ) = e
80+ )
81+ }
82+ }
83+
5184/**
5285 * A check against a regular expression, considered as a barrier guard.
5386 *
5487 * This is overapproximate: we do not attempt to reason about the correctness of the regexp.
5588 */
5689class RegexpCheckBarrier extends DataFlow:: Node {
57- RegexpCheckBarrier ( ) {
58- this = DataFlow:: BarrierGuard< regexpMatchGuardChecks / 3 > :: getABarrierNode ( )
59- or
60- // Annotations don't fit into the model of barrier guards because the
61- // annotation doesn't dominate the sanitized expression, so we instead
62- // treat them as barriers directly.
63- exists ( RegexMatch rm | rm instanceof Annotation | this .asExpr ( ) = rm .getString ( ) )
64- }
90+ RegexpCheckBarrier ( ) { this = RegexMatchBarrier< regexpMatchGuardChecks / 3 > :: getABarrierNode ( ) }
6591}
6692
6793/**
0 commit comments