@@ -32,12 +32,24 @@ module ModificationOfParameterWithDefault {
32
32
abstract class Barrier extends DataFlow:: Node { }
33
33
34
34
/**
35
- * A sanitizer guard for detecting modifications of a parameters default value.
35
+ * A sanitizer guard that does not let a truthy value flow to the true branch.
36
+ *
37
+ * Since guards with different behaviour cannot exist on the same node,
38
+ * we let all guards have the same behaviour, in the sense that they all check
39
+ * the true branch. Instead, we partition guards into those that block
40
+ * truthy values and those that block falsy values.
36
41
*/
37
- abstract class BarrierGuard extends DataFlow:: BarrierGuard {
38
- /** Result is true if this guard blocks non-empty values and false if it blocks empty values. */
39
- abstract boolean blocksNonEmpty ( ) ;
40
- }
42
+ abstract class BlocksTruthy extends DataFlow:: BarrierGuard { }
43
+
44
+ /**
45
+ * A sanitizer guard that does not let a falsy value flow to the true branch.
46
+ *
47
+ * Since guards with different behaviour cannot exist on the same node,
48
+ * we let all guards have the same behaviour, in the sense that they all check
49
+ * the true branch. Instead, we partition guards into those that block
50
+ * truthy values and those that block falsy values.
51
+ */
52
+ abstract class BlocksFalsey extends DataFlow:: BarrierGuard { }
41
53
42
54
/** Gets the truthiness (non emptyness) of the default of `p` if that value is mutable */
43
55
private boolean mutableDefaultValue ( Parameter p ) {
@@ -147,30 +159,46 @@ module ModificationOfParameterWithDefault {
147
159
boolean isInverted ( ) { result = inverted }
148
160
}
149
161
150
- /**
151
- * A check for the value being truthy or falsy can guard against modifying the default value.
152
- */
153
- class IdentityGuard extends BarrierGuard {
154
- ControlFlowNode checked_node ;
155
- boolean safe_branch ;
156
- boolean nonEmpty ;
162
+ boolean isIdentityGuard ( DataFlow:: GuardNode guard , ControlFlowNode guarded ) {
163
+ exists ( IdentityGuarded ig |
164
+ ig instanceof Name and
165
+ // In `not l`, the `ControlFlowNode` for `l` is not an instance of `GuardNode`.
166
+ // TODO: This is slightly naive, we should change it when we have a proper guards library.
167
+ guard .getNode ( ) .getAChildNode * ( ) = ig and
168
+ result = ig .isInverted ( ) and
169
+ guarded .getNode ( ) = ig
170
+ )
171
+ }
157
172
158
- IdentityGuard ( ) {
159
- nonEmpty in [ true , false ] and
160
- exists ( IdentityGuarded ig |
161
- this .getNode ( ) = ig and
162
- checked_node = this and
163
- // The raw guard is true if the value is non-empty.
164
- // So we are safe either if we are looking for a non-empty value
165
- // or if we are looking for an empty value and the guard is inverted.
166
- safe_branch = ig .isInverted ( ) .booleanXor ( nonEmpty )
167
- )
173
+ class BlocksTruthyGuard extends BlocksTruthy {
174
+ ControlFlowNode guarded ;
175
+
176
+ BlocksTruthyGuard ( ) {
177
+ // The raw guard is true if the value is non-empty.
178
+ // We wish to send truthy falues to the false branch,
179
+ // se we are looking for inverted guards.
180
+ isIdentityGuard ( this , guarded ) = true
168
181
}
169
182
170
183
override predicate checks ( ControlFlowNode node , boolean branch ) {
171
- node = checked_node and branch = safe_branch
184
+ node = guarded and
185
+ branch = true
172
186
}
187
+ }
188
+
189
+ class BlocksFalseyGuard extends BlocksFalsey {
190
+ ControlFlowNode guarded ;
173
191
174
- override boolean blocksNonEmpty ( ) { result = nonEmpty }
192
+ BlocksFalseyGuard ( ) {
193
+ // The raw guard is true if the value is non-empty.
194
+ // We wish to send falsy falues to the false branch,
195
+ // se we are looking for guards that are not inverted.
196
+ isIdentityGuard ( this , guarded ) = false
197
+ }
198
+
199
+ override predicate checks ( ControlFlowNode node , boolean branch ) {
200
+ node = guarded and
201
+ branch = true
202
+ }
175
203
}
176
204
}
0 commit comments