Skip to content

Commit d680039

Browse files
committed
Guards: Support disjunctive implications.
1 parent 2192d75 commit d680039

File tree

3 files changed

+104
-3
lines changed

3 files changed

+104
-3
lines changed

java/ql/test/query-tests/Nullness/C.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ public void ex19(Object t, Object x) {
261261
if (t != null) {
262262
t.hashCode(); // OK
263263
} else {
264-
x.hashCode(); // NPE - false positive
264+
x.hashCode(); // OK
265265
}
266266
}
267267
}

java/ql/test/query-tests/Nullness/NullMaybe.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
| C.java:144:15:144:15 | a | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:141:20:141:26 | a | a | C.java:142:13:142:21 | ... == ... | this |
3636
| C.java:219:9:219:10 | o1 | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:212:20:212:28 | o1 | o1 | C.java:213:9:213:18 | ... == ... | this |
3737
| C.java:233:7:233:8 | xs | Variable $@ may be null at this access because of $@ assignment. | C.java:231:5:231:56 | int[] xs | xs | C.java:231:11:231:55 | xs | this |
38-
| C.java:264:9:264:9 | x | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:258:30:258:37 | x | x | C.java:259:30:259:38 | ... != ... | this |
3938
| F.java:11:5:11:7 | obj | Variable $@ may be null at this access as suggested by $@ null guard. | F.java:8:18:8:27 | obj | obj | F.java:9:9:9:19 | ... == ... | this |
4039
| F.java:17:5:17:7 | obj | Variable $@ may be null at this access as suggested by $@ null guard. | F.java:14:18:14:27 | obj | obj | F.java:15:9:15:19 | ... == ... | this |
4140
| G.java:20:12:20:12 | s | Variable $@ may be null at this access as suggested by $@ null guard. | G.java:3:27:3:34 | s | s | G.java:5:9:5:17 | ... == ... | this |

shared/controlflow/codeql/controlflow/Guards.qll

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,9 @@ module Make<
926926
guardControls(g0, v0, tgtGuard, tgtVal) and
927927
additionalImpliesStep(g0, v0, guard, v)
928928
)
929+
or
930+
baseGuardValue(tgtGuard, tgtVal) and
931+
disjunctiveGuardControls(guard, v, tgtGuard, tgtVal)
929932
}
930933

931934
/**
@@ -1003,6 +1006,104 @@ module Make<
10031006
)
10041007
}
10051008

1009+
private import DisjunctiveGuard
1010+
1011+
private module DisjunctiveGuard {
1012+
/**
1013+
* Holds if `disjunction` evaluating to `val` means that either
1014+
* `disjunct1` or `disjunct2` is `val`.
1015+
*/
1016+
private predicate disjunction(
1017+
Guard disjunction, GuardValue val, Guard disjunct1, Guard disjunct2
1018+
) {
1019+
2 =
1020+
strictcount(Guard op |
1021+
disjunction.(OrExpr).getAnOperand() = op or disjunction.(AndExpr).getAnOperand() = op
1022+
) and
1023+
disjunct1 != disjunct2 and
1024+
(
1025+
exists(OrExpr d | d = disjunction |
1026+
d.getAnOperand() = disjunct1 and
1027+
d.getAnOperand() = disjunct2 and
1028+
val.asBooleanValue() = true
1029+
)
1030+
or
1031+
exists(AndExpr d | d = disjunction |
1032+
d.getAnOperand() = disjunct1 and
1033+
d.getAnOperand() = disjunct2 and
1034+
val.asBooleanValue() = false
1035+
)
1036+
)
1037+
}
1038+
1039+
private predicate disjunct(Guard guard, GuardValue val) { disjunction(_, val, guard, _) }
1040+
1041+
module DisjunctImplies = ImpliesTC<disjunct/2>;
1042+
1043+
/**
1044+
* Holds if one of the disjuncts in `disjunction` evaluating to `dv` implies that `def`
1045+
* evaluates to `v`. The other disjunct is `otherDisjunct`.
1046+
*/
1047+
pragma[nomagic]
1048+
private predicate ssaControlsDisjunct(
1049+
SsaDefinition def, GuardValue v, Guard disjunction, Guard otherDisjunct, GuardValue dv
1050+
) {
1051+
exists(Guard disjunct |
1052+
disjunction(disjunction, dv, disjunct, otherDisjunct) and
1053+
DisjunctImplies::ssaControls(def, v, disjunct, dv)
1054+
)
1055+
}
1056+
1057+
/**
1058+
* Holds if the disjunction of `def` evaluating to `v` and
1059+
* `otherDisjunct` evaluating to `dv` controls `bb`.
1060+
*/
1061+
pragma[nomagic]
1062+
private predicate ssaDisjunctionControls(
1063+
SsaDefinition def, GuardValue v, Guard otherDisjunct, GuardValue dv, BasicBlock bb
1064+
) {
1065+
exists(Guard disjunction |
1066+
ssaControlsDisjunct(def, v, disjunction, otherDisjunct, dv) and
1067+
disjunction.valueControls(bb, dv)
1068+
)
1069+
}
1070+
1071+
/**
1072+
* Holds if `tgtGuard` evaluating to `tgtVal` implies that `def`
1073+
* evaluates to `v`. The basic block of `tgtGuard` is `bb`.
1074+
*/
1075+
pragma[nomagic]
1076+
private predicate ssaControlsGuard(
1077+
SsaDefinition def, GuardValue v, Guard tgtGuard, GuardValue tgtVal, BasicBlock bb
1078+
) {
1079+
(
1080+
BranchImplies::ssaControls(def, v, tgtGuard, tgtVal) or
1081+
WrapperGuard::ReturnImplies::ssaControls(def, v, tgtGuard, tgtVal)
1082+
) and
1083+
tgtGuard.getBasicBlock() = bb
1084+
}
1085+
1086+
/**
1087+
* Holds if `tgtGuard` evaluating to `tgtVal` implies that `guard`
1088+
* evaluates to `v`.
1089+
*/
1090+
pragma[nomagic]
1091+
predicate disjunctiveGuardControls(
1092+
Guard guard, GuardValue v, Guard tgtGuard, GuardValue tgtVal
1093+
) {
1094+
exists(SsaDefinition def, GuardValue v1, GuardValue v2, BasicBlock bb |
1095+
// If `def==v1 || guard==v` controls `bb`,
1096+
ssaDisjunctionControls(def, v1, guard, v, bb) and
1097+
// and `tgtGuard==tgtVal` in `bb` implies `def==v2`,
1098+
ssaControlsGuard(def, v2, tgtGuard, tgtVal, bb) and
1099+
// and `v1` and `v2` are disjoint,
1100+
disjointValues(v1, v2)
1101+
// then assuming `tgtGuard==tgtVal` it follows that `def` cannot be `v1`
1102+
// and therefore we must have `guard==v`.
1103+
)
1104+
}
1105+
}
1106+
10061107
/**
10071108
* Provides an implementation of guard implication logic for guard
10081109
* wrappers.
@@ -1021,7 +1122,8 @@ module Make<
10211122

10221123
private predicate relevantCallValue(NonOverridableMethodCall call, GuardValue val) {
10231124
BranchImplies::guardControls(call, val, _, _) or
1024-
ReturnImplies::guardControls(call, val, _, _)
1125+
ReturnImplies::guardControls(call, val, _, _) or
1126+
DisjunctImplies::guardControls(call, val, _, _)
10251127
}
10261128

10271129
predicate relevantReturnValue(NonOverridableMethod m, GuardValue val) {

0 commit comments

Comments
 (0)