@@ -32,12 +32,24 @@ module ModificationOfParameterWithDefault {
3232 abstract class Barrier extends DataFlow:: Node { }
3333
3434 /**
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.
3641 */
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 { }
4153
4254 /** Gets the truthiness (non emptyness) of the default of `p` if that value is mutable */
4355 private boolean mutableDefaultValue ( Parameter p ) {
@@ -147,30 +159,46 @@ module ModificationOfParameterWithDefault {
147159 boolean isInverted ( ) { result = inverted }
148160 }
149161
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+ }
157172
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
168181 }
169182
170183 override predicate checks ( ControlFlowNode node , boolean branch ) {
171- node = checked_node and branch = safe_branch
184+ node = guarded and
185+ branch = true
172186 }
187+ }
188+
189+ class BlocksFalseyGuard extends BlocksFalsey {
190+ ControlFlowNode guarded ;
173191
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+ }
175203 }
176204}
0 commit comments