Skip to content

Commit 2bdf423

Browse files
committed
Python: Fix up pruning in QL to better handle constraints from constants.
1 parent 12c906c commit 2bdf423

File tree

8 files changed

+244
-155
lines changed

8 files changed

+244
-155
lines changed

python/ql/src/semmle/python/Exprs.qll

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,6 @@ abstract class ImmutableLiteral extends Expr {
346346
abstract Object getLiteralObject();
347347

348348
abstract boolean booleanValue();
349-
350349
}
351350

352351
/** A numerical constant expression, such as `7` or `4.2` */
@@ -422,7 +421,6 @@ class FloatLiteral extends Num {
422421
or
423422
this.getValue() != 0.0 and this.getValue() != -0.0 and result = true
424423
}
425-
426424
}
427425

428426
/** An imaginary numeric constant, such as `3j` */
@@ -474,6 +472,10 @@ class NegativeIntegerLiteral extends ImmutableLiteral, UnaryExpr {
474472
py_cobjectnames(result, "-" + this.getOperand().(IntegerLiteral).getN())
475473
}
476474

475+
int getValue() {
476+
result = -this.getOperand().(IntegerLiteral).getValue()
477+
}
478+
477479
}
478480

479481
/** A unicode string expression, such as `u"\u20ac"`. Note that unadorned string constants such as
@@ -802,7 +804,6 @@ class None extends NameConstant {
802804
override boolean booleanValue() {
803805
result = false
804806
}
805-
806807
}
807808

808809
/** An await expression such as `await coro`. */

python/ql/src/semmle/python/Pruning.qll

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ module Pruner {
156156
private import Comparisons
157157
private import SSA
158158

159+
private int intValue(ImmutableLiteral lit) {
160+
result = lit.(IntegerLiteral).getValue()
161+
or
162+
result = lit.(NegativeIntegerLiteral).getValue()
163+
}
164+
159165
newtype TConstraint =
160166
TTruthy(boolean b) { b = true or b = false }
161167
or
@@ -164,7 +170,7 @@ module Pruner {
164170
TConstrainedByConstant(CompareOp op, int k) {
165171
int_test(_, _, op, k)
166172
or
167-
exists(Assign a | a.getValue().(IntegerLiteral).getValue() = k) and op = eq()
173+
exists(Assign a | intValue(a.getValue()) = k) and op = eq()
168174
}
169175

170176
/** A constraint that may be applied to an SSA variable.
@@ -450,56 +456,48 @@ module Pruner {
450456
|
451457
op.forOp(cop) and
452458
py_ssa_use(left, var) and
453-
right.getNode().(IntegerLiteral).getValue() = k
459+
intValue(right.getNode()) = k
454460
or
455461
op.reverse().forOp(cop) and
456462
py_ssa_use(right, var) and
457-
left.getNode().(IntegerLiteral).getValue() = k
463+
intValue(left.getNode()) = k
458464
)
459465
or
460466
int_test(test.(UnprunedNot).getOperand(), var, op.invert(), k)
461467
}
462468

463-
predicate int_assignment(UnprunedCfgNode asgn, SsaVariable var, CompareOp op, int k) {
464-
exists(Assign a |
465-
a.getATarget() = asgn.getNode() and
466-
py_ssa_use(asgn, var) and
467-
k = a.getValue().(IntegerLiteral).getValue() and
468-
op = eq()
469-
)
470-
}
471-
472-
predicate none_assignment(UnprunedCfgNode asgn, SsaVariable var) {
473-
exists(Assign a |
474-
a.getATarget() = asgn.getNode() and
475-
py_ssa_use(asgn, var) and
476-
a.getValue() instanceof None
469+
private predicate constrainingValue(Expr e) {
470+
exists(Assign a, UnprunedCfgNode asgn |
471+
a.getValue() = e and a.getATarget() = asgn.getNode() and py_ssa_defn(_, asgn)
477472
)
473+
or
474+
exists(UnaryExpr n | constrainingValue(n) and n.getOp() instanceof Not and e = n.getOperand())
478475
}
479476

480-
boolean truthy_assignment(UnprunedCfgNode asgn, SsaVariable var) {
481-
exists(Assign a |
482-
a.getATarget() = asgn.getNode() and
483-
py_ssa_use(asgn, var)
484-
|
485-
a.getValue() instanceof True and result = true
477+
private Constraint constraintFromValue(Expr e) {
478+
constrainingValue(e) and
479+
(
480+
result = TConstrainedByConstant(eq(), intValue(e))
481+
or
482+
e instanceof True and result = TTruthy(true)
486483
or
487-
a.getValue() instanceof False and result = false
484+
e instanceof False and result = TTruthy(false)
485+
or
486+
e instanceof None and result = TIsNone(true)
487+
or
488+
result = constraintFromValue(e.(UnaryExpr).getOperand()).invert()
488489
)
489-
or
490-
module_import(asgn, var) and result = true
491490
}
492491

493492
/** Gets the constraint on `var` resulting from the assignment in `asgn` */
494-
Constraint constraintFromAssignment(SsaVariable var, UnprunedBasicBlock asgn) {
495-
exists(CompareOp op, int k |
496-
int_assignment(asgn.getANode(), var, op, k) and
497-
result = TConstrainedByConstant(op, k)
493+
Constraint constraintFromAssignment(SsaVariable var, UnprunedCfgNode asgn) {
494+
exists(Assign a |
495+
a.getATarget() = asgn.getNode() and
496+
py_ssa_defn(var, asgn) and
497+
result = constraintFromValue(a.getValue())
498498
)
499499
or
500-
none_assignment(asgn.getANode(), var) and result = TIsNone(true)
501-
or
502-
result = TTruthy(truthy_assignment(asgn.getANode(), var))
500+
module_import(asgn, var) and result = TTruthy(true)
503501
}
504502

505503
/** Holds if the constraint `preval` holds for `var` on edge `pred` -> `succ` as a result of a prior test or assignment */
@@ -518,7 +516,7 @@ module Pruner {
518516
first.(UnprunedConditionBlock).controlsEdge(pred, succ, false) and
519517
preval = constraintFromTest(var, first.last()).invert()
520518
or
521-
preval = constraintFromAssignment(var, first) and
519+
preval = constraintFromAssignment(var, first.getANode()) and
522520
first.dominates(pred) and
523521
(succ = pred.getAFalseSuccessor() or succ = pred.getATrueSuccessor())
524522
)
Lines changed: 130 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,130 @@
1-
| 8 | test | test | Truthy |
2-
| 10 | test | test | Truthy |
3-
| 14 | seq | seq | Truthy |
4-
| 16 | seq | seq | Truthy |
5-
| 17 | seq | seq | Truthy |
6-
| 21 | UnaryExpr | t1 | Falsey |
7-
| 21 | t1 | t1 | Truthy |
8-
| 24 | t1 | t1 | Truthy |
9-
| 25 | t1 | t1 | Truthy |
10-
| 26 | t2 | t2 | Truthy |
11-
| 29 | t2 | t2 | Truthy |
12-
| 30 | t2 | t2 | Truthy |
13-
| 31 | t3 | t3 | Truthy |
14-
| 31 | t4 | t4 | Truthy |
15-
| 32 | t3 | t3 | Truthy |
16-
| 33 | t3 | t3 | Truthy |
17-
| 34 | t3 | t3 | Truthy |
18-
| 35 | t4 | t4 | Truthy |
19-
| 36 | t5 | t5 | Truthy |
20-
| 36 | t6 | t6 | Truthy |
21-
| 37 | t5 | t5 | Truthy |
22-
| 38 | t5 | t5 | Truthy |
23-
| 39 | t6 | t6 | Truthy |
24-
| 40 | t6 | t6 | Truthy |
25-
| 43 | t1 | t1 | Truthy |
26-
| 44 | UnaryExpr | t2 | Falsey |
27-
| 44 | t2 | t2 | Truthy |
28-
| 47 | t1 | t1 | Truthy |
29-
| 48 | t2 | t2 | Truthy |
30-
| 49 | t2 | t2 | Truthy |
31-
| 51 | t2 | t2 | Truthy |
32-
| 52 | t2 | t2 | Truthy |
33-
| 55 | seq1 | seq1 | Truthy |
34-
| 57 | UnaryExpr | seq2 | Falsey |
35-
| 57 | seq2 | seq2 | Truthy |
36-
| 60 | seq1 | seq1 | Truthy |
37-
| 62 | seq1 | seq1 | Truthy |
38-
| 63 | seq2 | seq2 | Truthy |
39-
| 65 | seq2 | seq2 | Truthy |
40-
| 66 | seq3 | seq3 | Truthy |
41-
| 68 | UnaryExpr | seq4 | Falsey |
42-
| 68 | seq4 | seq4 | Truthy |
43-
| 71 | seq3 | seq3 | Truthy |
44-
| 73 | var | var | Truthy |
45-
| 74 | seq4 | seq4 | Truthy |
46-
| 76 | var | var | Truthy |
47-
| 78 | seq5 | seq5 | Truthy |
48-
| 80 | seq5 | seq5 | Truthy |
49-
| 81 | seq5 | seq5 | Truthy |
50-
| 83 | var | var | Truthy |
51-
| 88 | UnaryExpr | x | Falsey |
52-
| 88 | x | x | Truthy |
53-
| 89 | Exception | Exception | Truthy |
54-
| 90 | y | y | Truthy |
55-
| 91 | Exception | Exception | Truthy |
56-
| 92 | make_a_call | make_a_call | Truthy |
57-
| 93 | UnaryExpr | x | Falsey |
58-
| 93 | x | x | Truthy |
59-
| 94 | count | count | Truthy |
60-
| 95 | y | y | Truthy |
61-
| 96 | count | count | Truthy |
62-
| 101 | make_a_call | make_a_call | Truthy |
63-
| 102 | UnaryExpr | another_module | Falsey |
64-
| 102 | another_module | another_module | Truthy |
65-
| 103 | count | count | Truthy |
66-
| 107 | UnaryExpr | t1 | Falsey |
67-
| 107 | t1 | t1 | Truthy |
68-
| 109 | t2 | t2 | Truthy |
69-
| 111 | t1 | t1 | Truthy |
70-
| 113 | UnaryExpr | t2 | Falsey |
71-
| 113 | t2 | t2 | Truthy |
72-
| 117 | UnaryExpr | test | Falsey |
73-
| 117 | test | test | Truthy |
74-
| 119 | UnaryExpr | test | Falsey |
75-
| 119 | test | test | Truthy |
76-
| 123 | m | m | Truthy |
77-
| 125 | m | m | Truthy |
78-
| 126 | m | m | Truthy |
79-
| 158 | Compare | ps | Is not None |
80-
| 158 | ps | ps | Truthy |
81-
| 159 | ps | ps | Truthy |
82-
| 160 | Compare | ps | Is None |
83-
| 160 | ps | ps | Truthy |
84-
| 171 | __name__ | __name__ | Truthy |
85-
| 172 | None | None | Truthy |
86-
| 174 | func | func | Truthy |
87-
| 175 | Exception | Exception | Truthy |
88-
| 176 | count | count | Truthy |
89-
| 177 | Compare | escapes | Is None |
90-
| 177 | None | None | Truthy |
91-
| 177 | escapes | escapes | Truthy |
92-
| 178 | count | count | Truthy |
93-
| 180 | count | count | Truthy |
94-
| 188 | true12 | true12 | Truthy |
95-
| 195 | Compare | x | < 4 |
96-
| 195 | x | x | Truthy |
97-
| 197 | Compare | x | < 4 |
98-
| 197 | x | x | Truthy |
99-
| 201 | Compare | x | < 4 |
100-
| 201 | x | x | Truthy |
101-
| 203 | Compare | x | >= 4 |
102-
| 203 | UnaryExpr | x | < 4 |
103-
| 203 | x | x | Truthy |
104-
| 207 | Compare | x | < 4 |
105-
| 207 | x | x | Truthy |
106-
| 209 | Compare | x | < 4 |
107-
| 209 | x | x | Truthy |
108-
| 214 | None | None | Truthy |
109-
| 215 | x | x | Truthy |
110-
| 215 | y | y | Truthy |
111-
| 217 | x | x | Truthy |
112-
| 217 | y | y | Truthy |
113-
| 219 | x | x | Truthy |
114-
| 223 | y | y | Truthy |
1+
| 8 | test | test | Truthy | test |
2+
| 10 | test | test | Truthy | test |
3+
| 14 | seq | seq | Truthy | test |
4+
| 16 | seq | seq | Truthy | test |
5+
| 17 | seq | seq | Truthy | test |
6+
| 21 | UnaryExpr | t1 | Falsey | test |
7+
| 21 | t1 | t1 | Truthy | test |
8+
| 24 | t1 | t1 | Truthy | test |
9+
| 25 | t1 | t1 | Truthy | test |
10+
| 26 | t2 | t2 | Truthy | test |
11+
| 29 | t2 | t2 | Truthy | test |
12+
| 30 | t2 | t2 | Truthy | test |
13+
| 31 | t3 | t3 | Truthy | test |
14+
| 31 | t4 | t4 | Truthy | test |
15+
| 32 | t3 | t3 | Truthy | test |
16+
| 33 | t3 | t3 | Truthy | test |
17+
| 34 | t3 | t3 | Truthy | test |
18+
| 35 | t4 | t4 | Truthy | test |
19+
| 36 | t5 | t5 | Truthy | test |
20+
| 36 | t6 | t6 | Truthy | test |
21+
| 37 | t5 | t5 | Truthy | test |
22+
| 38 | t5 | t5 | Truthy | test |
23+
| 39 | t6 | t6 | Truthy | test |
24+
| 40 | t6 | t6 | Truthy | test |
25+
| 43 | t1 | t1 | Truthy | test |
26+
| 44 | UnaryExpr | t2 | Falsey | test |
27+
| 44 | t2 | t2 | Truthy | test |
28+
| 47 | t1 | t1 | Truthy | test |
29+
| 48 | t2 | t2 | Truthy | test |
30+
| 49 | t2 | t2 | Truthy | test |
31+
| 51 | t2 | t2 | Truthy | test |
32+
| 52 | t2 | t2 | Truthy | test |
33+
| 55 | seq1 | seq1 | Truthy | test |
34+
| 57 | UnaryExpr | seq2 | Falsey | test |
35+
| 57 | seq2 | seq2 | Truthy | test |
36+
| 60 | seq1 | seq1 | Truthy | test |
37+
| 62 | seq1 | seq1 | Truthy | test |
38+
| 63 | seq2 | seq2 | Truthy | test |
39+
| 65 | seq2 | seq2 | Truthy | test |
40+
| 66 | seq3 | seq3 | Truthy | test |
41+
| 68 | UnaryExpr | seq4 | Falsey | test |
42+
| 68 | seq4 | seq4 | Truthy | test |
43+
| 71 | seq3 | seq3 | Truthy | test |
44+
| 73 | var | var | Truthy | test |
45+
| 74 | seq4 | seq4 | Truthy | test |
46+
| 76 | var | var | Truthy | test |
47+
| 78 | seq5 | seq5 | Truthy | test |
48+
| 80 | seq5 | seq5 | Truthy | test |
49+
| 81 | seq5 | seq5 | Truthy | test |
50+
| 83 | var | var | Truthy | test |
51+
| 88 | UnaryExpr | x | Falsey | test |
52+
| 88 | x | x | Truthy | test |
53+
| 89 | Exception | Exception | Truthy | test |
54+
| 90 | y | y | Truthy | test |
55+
| 91 | Exception | Exception | Truthy | test |
56+
| 92 | make_a_call | make_a_call | Truthy | test |
57+
| 93 | UnaryExpr | x | Falsey | test |
58+
| 93 | x | x | Truthy | test |
59+
| 94 | count | count | Truthy | test |
60+
| 95 | y | y | Truthy | test |
61+
| 96 | count | count | Truthy | test |
62+
| 99 | another_module | another_module | Truthy | assign |
63+
| 101 | make_a_call | make_a_call | Truthy | test |
64+
| 102 | UnaryExpr | another_module | Falsey | test |
65+
| 102 | another_module | another_module | Truthy | test |
66+
| 103 | count | count | Truthy | test |
67+
| 107 | UnaryExpr | t1 | Falsey | test |
68+
| 107 | t1 | t1 | Truthy | test |
69+
| 109 | t2 | t2 | Truthy | test |
70+
| 111 | t1 | t1 | Truthy | test |
71+
| 113 | UnaryExpr | t2 | Falsey | test |
72+
| 113 | t2 | t2 | Truthy | test |
73+
| 117 | UnaryExpr | test | Falsey | test |
74+
| 117 | test | test | Truthy | test |
75+
| 119 | UnaryExpr | test | Falsey | test |
76+
| 119 | test | test | Truthy | test |
77+
| 123 | m | m | Truthy | test |
78+
| 125 | m | m | Truthy | test |
79+
| 126 | m | m | Truthy | test |
80+
| 158 | Compare | ps | Is not None | test |
81+
| 158 | ps | ps | Truthy | test |
82+
| 159 | ps | ps | Truthy | test |
83+
| 160 | Compare | ps | Is None | test |
84+
| 160 | ps | ps | Truthy | test |
85+
| 171 | __name__ | __name__ | Truthy | test |
86+
| 172 | None | None | Truthy | test |
87+
| 172 | escapes | escapes | Is None | assign |
88+
| 174 | func | func | Truthy | test |
89+
| 175 | Exception | Exception | Truthy | test |
90+
| 176 | count | count | Truthy | test |
91+
| 177 | Compare | escapes | Is None | test |
92+
| 177 | None | None | Truthy | test |
93+
| 177 | escapes | escapes | Truthy | test |
94+
| 178 | count | count | Truthy | test |
95+
| 180 | count | count | Truthy | test |
96+
| 188 | true12 | true12 | Truthy | test |
97+
| 191 | true12 | true12 | == 0 | assign |
98+
| 195 | Compare | x | < 4 | test |
99+
| 195 | x | x | Truthy | test |
100+
| 197 | Compare | x | < 4 | test |
101+
| 197 | x | x | Truthy | test |
102+
| 201 | Compare | x | < 4 | test |
103+
| 201 | x | x | Truthy | test |
104+
| 203 | Compare | x | >= 4 | test |
105+
| 203 | UnaryExpr | x | < 4 | test |
106+
| 203 | x | x | Truthy | test |
107+
| 207 | Compare | x | < 4 | test |
108+
| 207 | x | x | Truthy | test |
109+
| 209 | Compare | x | < 4 | test |
110+
| 209 | x | x | Truthy | test |
111+
| 214 | None | None | Truthy | test |
112+
| 215 | x | x | Truthy | test |
113+
| 215 | y | y | Truthy | test |
114+
| 217 | x | x | Truthy | test |
115+
| 217 | y | y | Truthy | test |
116+
| 219 | x | x | Truthy | test |
117+
| 223 | y | y | Truthy | test |
118+
| 229 | k | k | Falsey | assign |
119+
| 230 | k | k | Truthy | test |
120+
| 237 | k | k | == 3 | assign |
121+
| 238 | k | k | Truthy | test |
122+
| 245 | k | k | Is None | assign |
123+
| 246 | k | k | Truthy | test |
124+
| 253 | a | a | Truthy | test |
125+
| 254 | k | k | Truthy | assign |
126+
| 256 | k | k | Falsey | assign |
127+
| 257 | k | k | Truthy | test |
128+
| 264 | var | var | Truthy | assign |
129+
| 266 | var | var | Falsey | assign |
130+
| 267 | var | var | Truthy | test |

0 commit comments

Comments
 (0)