@@ -36,22 +36,23 @@ abstract class RegexCreation extends DataFlow::Node {
36
36
* created from.
37
37
*/
38
38
abstract DataFlow:: Node getStringInput ( ) ;
39
+
40
+ /**
41
+ * Gets a dataflow node for the options input that might contain parse mode
42
+ * flags (if any).
43
+ */
44
+ DataFlow:: Node getOptionsInput ( ) { none ( ) }
39
45
}
40
46
41
47
/**
42
- * A data-flow node where a `Regex` or `NSRegularExpression` object is created.
48
+ * A data-flow node where a `Regex` object is created.
43
49
*/
44
- private class StandardRegexCreation extends RegexCreation {
50
+ private class RegexRegexCreation extends RegexCreation {
45
51
DataFlow:: Node input ;
46
52
47
- StandardRegexCreation ( ) {
53
+ RegexRegexCreation ( ) {
48
54
exists ( CallExpr call |
49
- (
50
- call .getStaticTarget ( ) .( Method ) .hasQualifiedName ( "Regex" , [ "init(_:)" , "init(_:as:)" ] ) or
51
- call .getStaticTarget ( )
52
- .( Method )
53
- .hasQualifiedName ( "NSRegularExpression" , "init(pattern:options:)" )
54
- ) and
55
+ call .getStaticTarget ( ) .( Method ) .hasQualifiedName ( "Regex" , [ "init(_:)" , "init(_:as:)" ] ) and
55
56
input .asExpr ( ) = call .getArgument ( 0 ) .getExpr ( ) and
56
57
this .asExpr ( ) = call
57
58
)
@@ -60,6 +61,29 @@ private class StandardRegexCreation extends RegexCreation {
60
61
override DataFlow:: Node getStringInput ( ) { result = input }
61
62
}
62
63
64
+ /**
65
+ * A data-flow node where an `NSRegularExpression` object is created.
66
+ */
67
+ private class NSRegularExpressionRegexCreation extends RegexCreation {
68
+ DataFlow:: Node input ;
69
+
70
+ NSRegularExpressionRegexCreation ( ) {
71
+ exists ( CallExpr call |
72
+ call .getStaticTarget ( )
73
+ .( Method )
74
+ .hasQualifiedName ( "NSRegularExpression" , "init(pattern:options:)" ) and
75
+ input .asExpr ( ) = call .getArgument ( 0 ) .getExpr ( ) and
76
+ this .asExpr ( ) = call
77
+ )
78
+ }
79
+
80
+ override DataFlow:: Node getStringInput ( ) { result = input }
81
+
82
+ override DataFlow:: Node getOptionsInput ( ) {
83
+ result .asExpr ( ) = this .asExpr ( ) .( CallExpr ) .getArgument ( 1 ) .getExpr ( )
84
+ }
85
+ }
86
+
63
87
newtype TRegexParseMode =
64
88
MkIgnoreCase ( ) or // case insensitive
65
89
MkVerbose ( ) or // ignores whitespace and `#` comments within patterns
@@ -94,25 +118,29 @@ class RegexAdditionalFlowStep extends Unit {
94
118
abstract predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) ;
95
119
96
120
/**
97
- * Holds if the step from `node1` to `node2` either sets (`isSet` = true)
98
- * or unsets (`isSet` = false) parse mode `mode` for the regular expression.
121
+ * Holds if a regular expression parse mode is either set (`isSet` = true)
122
+ * or unset (`isSet` = false) at `node`. Parse modes propagate through
123
+ * array construction and regex constuction.
99
124
*/
100
- abstract predicate modifiesParseMode (
101
- DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo , RegexParseMode mode , boolean isSet
102
- ) ;
125
+ abstract predicate setsParseMode ( DataFlow:: Node node , RegexParseMode mode , boolean isSet ) ;
103
126
}
104
127
105
128
/**
106
- * An additional flow step for `Regex` or `NSRegularExpression` .
129
+ * An additional flow step for `Regex`.
107
130
*/
108
- class StandardRegexAdditionalFlowStep extends RegexAdditionalFlowStep {
131
+ class RegexRegexAdditionalFlowStep extends RegexAdditionalFlowStep {
109
132
override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
110
- this .modifiesParseMode ( nodeFrom , nodeTo , _, _)
133
+ this .setsParseModeEdge ( nodeFrom , nodeTo , _, _)
111
134
}
112
135
113
- override predicate modifiesParseMode (
136
+ override predicate setsParseMode ( DataFlow:: Node node , RegexParseMode mode , boolean isSet ) {
137
+ this .setsParseModeEdge ( _, node , mode , isSet )
138
+ }
139
+
140
+ private predicate setsParseModeEdge (
114
141
DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo , RegexParseMode mode , boolean isSet
115
142
) {
143
+ // `Regex` methods that modify parse mode
116
144
exists ( CallExpr ce |
117
145
nodeFrom .asExpr ( ) = ce .getQualifier ( ) and
118
146
nodeTo .asExpr ( ) = ce and
@@ -135,6 +163,56 @@ class StandardRegexAdditionalFlowStep extends RegexAdditionalFlowStep {
135
163
}
136
164
}
137
165
166
+ /**
167
+ * An additional flow step for `NSRegularExpression`.
168
+ */
169
+ class StandardRegexAdditionalFlowStep extends RegexAdditionalFlowStep {
170
+ override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) { none ( ) }
171
+
172
+ override predicate setsParseMode ( DataFlow:: Node node , RegexParseMode mode , boolean isSet ) {
173
+ // `NSRegularExpression.Options` values
174
+ node .asExpr ( )
175
+ .( MemberRefExpr )
176
+ .getMember ( )
177
+ .( FieldDecl )
178
+ .hasQualifiedName ( "NSRegularExpression.Options" , "caseInsensitive" ) and
179
+ mode = MkIgnoreCase ( ) and
180
+ isSet = true
181
+ or
182
+ node .asExpr ( )
183
+ .( MemberRefExpr )
184
+ .getMember ( )
185
+ .( FieldDecl )
186
+ .hasQualifiedName ( "NSRegularExpression.Options" , "allowCommentsAndWhitespace" ) and
187
+ mode = MkVerbose ( ) and
188
+ isSet = true
189
+ or
190
+ node .asExpr ( )
191
+ .( MemberRefExpr )
192
+ .getMember ( )
193
+ .( FieldDecl )
194
+ .hasQualifiedName ( "NSRegularExpression.Options" , "dotMatchesLineSeparators" ) and
195
+ mode = MkDotAll ( ) and
196
+ isSet = true
197
+ or
198
+ node .asExpr ( )
199
+ .( MemberRefExpr )
200
+ .getMember ( )
201
+ .( FieldDecl )
202
+ .hasQualifiedName ( "NSRegularExpression.Options" , "anchorsMatchLines" ) and
203
+ mode = MkMultiLine ( ) and
204
+ isSet = true
205
+ or
206
+ node .asExpr ( )
207
+ .( MemberRefExpr )
208
+ .getMember ( )
209
+ .( FieldDecl )
210
+ .hasQualifiedName ( "NSRegularExpression.Options" , "useUnicodeWordBoundaries" ) and
211
+ mode = MkUnicode ( ) and
212
+ isSet = true
213
+ }
214
+ }
215
+
138
216
/**
139
217
* A call that evaluates a regular expression. For example, the call to `firstMatch` in:
140
218
* ```
@@ -174,7 +252,7 @@ abstract class RegexEval extends CallExpr {
174
252
RegexParseMode getAParseMode ( ) {
175
253
exists ( DataFlow:: Node setNode |
176
254
// parse mode flag is set
177
- any ( RegexAdditionalFlowStep s ) .modifiesParseMode ( _ , setNode , result , true ) and
255
+ any ( RegexAdditionalFlowStep s ) .setsParseMode ( setNode , result , true ) and
178
256
// reaches this eval
179
257
RegexParseModeFlow:: flow ( setNode , DataFlow:: exprNode ( this .getRegexInput ( ) ) )
180
258
)
0 commit comments