Skip to content

Commit a1a3c55

Browse files
skchofacebook-github-bot
authored andcommitted
[inferbo] Fix a bug in interval prune
Summary: This diff avoids that an invalid interval value, e.g. [0, -1], is genrated by interval pruning. Reviewed By: ezgicicek Differential Revision: D20645488 fbshipit-source-id: 6516c75d1
1 parent c73feb8 commit a1a3c55

File tree

3 files changed

+36
-34
lines changed

3 files changed

+36
-34
lines changed

infer/src/bufferoverrun/itv.ml

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -459,18 +459,22 @@ module ItvPure = struct
459459

460460
let arith_unop (unop : Unop.t) x = match unop with Neg -> Some (neg x) | BNot | LNot -> None
461461

462-
let prune_le : t -> t -> t = fun (l1, u1) (_, u2) -> (l1, Bound.overapprox_min u1 u2)
462+
let prune_le : t -> t -> t bottom_lifted =
463+
fun (l1, u1) (_, u2) -> normalize (l1, Bound.overapprox_min u1 u2)
463464

464-
let prune_ge : t -> t -> t = fun (l1, u1) (l2, _) -> (Bound.underapprox_max l1 l2, u1)
465465

466-
let prune_lt : t -> t -> t = fun x y -> prune_le x (minus y one)
466+
let prune_ge : t -> t -> t bottom_lifted =
467+
fun (l1, u1) (l2, _) -> normalize (Bound.underapprox_max l1 l2, u1)
467468

468-
let prune_gt : t -> t -> t = fun x y -> prune_ge x (plus y one)
469+
470+
let prune_lt : t -> t -> t bottom_lifted = fun x y -> prune_le x (minus y one)
471+
472+
let prune_gt : t -> t -> t bottom_lifted = fun x y -> prune_ge x (plus y one)
469473

470474
let prune_diff : t -> Bound.t -> t bottom_lifted =
471475
fun ((l, u) as itv) b ->
472-
if Bound.le b l then normalize (prune_gt itv (of_bound b))
473-
else if Bound.le u b then normalize (prune_lt itv (of_bound b))
476+
if Bound.le b l then prune_gt itv (of_bound b)
477+
else if Bound.le u b then prune_lt itv (of_bound b)
474478
else NonBottom itv
475479

476480

@@ -480,20 +484,17 @@ module ItvPure = struct
480484
fun c x y ->
481485
if is_invalid y then NonBottom x
482486
else
483-
let x =
484-
match c with
485-
| Le ->
486-
prune_le x y
487-
| Ge ->
488-
prune_ge x y
489-
| Lt ->
490-
prune_lt x y
491-
| Gt ->
492-
prune_gt x y
493-
| _ ->
494-
assert false
495-
in
496-
normalize x
487+
match c with
488+
| Le ->
489+
prune_le x y
490+
| Ge ->
491+
prune_ge x y
492+
| Lt ->
493+
prune_lt x y
494+
| Gt ->
495+
prune_gt x y
496+
| _ ->
497+
assert false
497498

498499

499500
let prune_eq : t -> t -> t bottom_lifted =
@@ -502,9 +503,7 @@ module ItvPure = struct
502503

503504

504505
let prune_eq_zero : t -> t bottom_lifted =
505-
fun x ->
506-
let x' = prune_le x zero in
507-
prune_ge x' zero |> normalize
506+
fun x -> match prune_le x zero with Bottom -> Bottom | NonBottom x' -> prune_ge x' zero
508507

509508

510509
let prune_ne : t -> t -> t bottom_lifted =
@@ -787,9 +786,9 @@ let prune_ge_one : t -> t = bind1 ItvPure.prune_ge_one
787786

788787
let prune_binop : Binop.t -> t -> t -> t = fun comp -> bind2 (ItvPure.prune_binop comp)
789788

790-
let prune_lt : t -> t -> t = lift2 ItvPure.prune_lt
789+
let prune_lt : t -> t -> t = bind2 ItvPure.prune_lt
791790

792-
let prune_le : t -> t -> t = lift2 ItvPure.prune_le
791+
let prune_le : t -> t -> t = bind2 ItvPure.prune_le
793792

794793
let prune_eq : t -> t -> t = bind2 ItvPure.prune_eq
795794

infer/tests/codetoanalyze/java/bufferoverrun/ArrayListTest.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,24 +251,27 @@ interface MyI {
251251
ArrayList<Integer> unknown_array_list1;
252252
ArrayList<Integer> unknown_array_list2;
253253

254-
void loop_on_unknown_iterator_FN(MyI x, int j) {
254+
void loop_on_unknown_iterator(MyI x, int j) {
255255
ArrayList<Integer> a = new ArrayList<>();
256256
ArrayList<Integer> b;
257257
if (unknown_bool) {
258258
b = a;
259259
} else {
260260
b = x.mk_unknown();
261261
}
262-
// `b` points to an zero-sized array and `Unknown` pointer here. By `b.hasNext()`, the size of
263-
// the array list is pruned incorrectly to [0,-1].
262+
// `b` points to an zero-sized array and `Unknown` pointer. Thus, the size of array list should
263+
// be evaluated to [0,+oo] in a sound design. However, this would harm overall analysis
264+
// precision with introducing a lot of FPs. To avoie that, we ignore the size of `Unknown`
265+
// array list here, instead we get some FNs.
264266
for (Integer i : b) {
265-
// Both branches are unreachable since `a.size()` is an invalid [0,-1].
267+
// `a.size()` is evaluated to bottom, rather than [0,+oo] here, but which does not make
268+
// branches unreachable.
266269
if (a.size() <= -1) {
267270
int[] c = new int[5];
268271
c[5] = 0;
269272
} else {
270-
int[] c = new int[5];
271-
c[5] = 0;
273+
int[] c = new int[10];
274+
c[10] = 0;
272275
}
273276
}
274277
}

infer/tests/codetoanalyze/java/bufferoverrun/issues.exp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.add_in_loop_i
2020
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.alias_join_bad():void, 10, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]
2121
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.alias_join_bad():void, 11, BUFFER_OVERRUN_L3, no_bucket, ERROR, [<Length trace>,Array declaration,Array access: Offset: 0 Size: [0, 2]]
2222
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.alloc_is_negative_bad():void, 0, INFERBO_ALLOC_IS_NEGATIVE, no_bucket, ERROR, [Allocation: Length: -1]
23-
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.loop_on_unknown_iterator_FN(ArrayListTest$MyI,int):void, 9, BUFFER_OVERRUN_U5, no_bucket, ERROR, [<Length trace>,Unknown value from: ArrayList ArrayListTest$MyI.mk_unknown(),Assignment,Array access: Offset: [-oo, +oo] Size: [0, +oo]]
24-
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.loop_on_unknown_iterator_FN(ArrayListTest$MyI,int):void, 11, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
25-
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.loop_on_unknown_iterator_FN(ArrayListTest$MyI,int):void, 11, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]
23+
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.loop_on_unknown_iterator(ArrayListTest$MyI,int):void, 11, BUFFER_OVERRUN_U5, no_bucket, ERROR, [<Length trace>,Unknown value from: ArrayList ArrayListTest$MyI.mk_unknown(),Assignment,Array access: Offset: [-oo, +oo] Size: [0, +oo]]
24+
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.loop_on_unknown_iterator(ArrayListTest$MyI,int):void, 16, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Length trace>,Array declaration,Array access: Offset: 5 Size: 5]
25+
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.loop_on_unknown_iterator(ArrayListTest$MyI,int):void, 19, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Length trace>,Array declaration,Array access: Offset: 10 Size: 10]
2626
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.multi_adds_in_loop_iterator_bad(java.util.ArrayList):void, 7, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Offset trace>,Parameter `b.elements[*]`,Assignment,<Length trace>,Array declaration,Array access: Offset: b.length + 1 Size: b.length]
2727
codetoanalyze/java/bufferoverrun/ArrayListTest.java, ArrayListTest.remove_in_loop_iterator_good_FP(java.util.ArrayList):void, 13, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Offset trace>,Parameter `b.elements[*]`,Assignment,<Length trace>,Parameter `b.elements[*]`,Array access: Offset: b.length Size: b.length]
2828
codetoanalyze/java/bufferoverrun/ArrayMember.java, codetoanalyze.java.bufferoverrun.ArrayMember.load_array_member_Bad():void, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Offset trace>,Parameter `this.buf[*]`,Assignment,<Length trace>,Array declaration,Array access: Offset: [max(10, this.buf[*].lb), min(10, this.buf[*].ub)] Size: 10]

0 commit comments

Comments
 (0)