Skip to content

Commit 315bd09

Browse files
authored
Merge pull request #1804 from goblint/issue-1803
Fix interval division
2 parents 0f224a8 + 0c6d1af commit 315bd09

File tree

6 files changed

+83
-35
lines changed

6 files changed

+83
-35
lines changed

src/cdomain/value/cdomains/int/intervalDomain.ml

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,12 @@ struct
6464
| Some _, None -> false
6565
| Some (x1,x2), Some (y1,y2) -> Ints_t.compare x1 y1 >= 0 && Ints_t.compare x2 y2 <= 0
6666

67-
let join ik (x:t) y =
67+
let join_no_norm ik (x:t) y =
6868
match x, y with
6969
| None, z | z, None -> z
70-
| Some (x1,x2), Some (y1,y2) -> norm ik @@ Some (Ints_t.min x1 y1, Ints_t.max x2 y2) |> fst
70+
| Some (x1,x2), Some (y1,y2) -> Some (Ints_t.min x1 y1, Ints_t.max x2 y2)
71+
72+
let join ik (x:t) y = norm ik @@ join_no_norm ik x y |> fst
7173

7274
let meet ik (x:t) y =
7375
match x, y with
@@ -292,16 +294,13 @@ struct
292294
match x, y with
293295
| None, None -> (bot (),{underflow=false; overflow=false})
294296
| None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))
295-
| (Some (x1,x2) as x), (Some (y1,y2) as y) ->
296-
begin
297-
let is_zero v = Ints_t.compare v Ints_t.zero = 0 in
298-
match y1, y2 with
299-
| l, u when is_zero l && is_zero u -> (top_of ik,{underflow=false; overflow=false})
300-
| l, _ when is_zero l -> div ik (Some (x1,x2)) (Some (Ints_t.one,y2))
301-
| _, u when is_zero u -> div ik (Some (x1,x2)) (Some (y1, Ints_t.(neg one)))
302-
| _ when leq (of_int ik (Ints_t.zero) |> fst) (Some (y1,y2)) -> (top_of ik,{underflow=false; overflow=false})
303-
| _ -> binary_op_with_norm IArith.div ik x y
304-
end
297+
| Some x, Some y ->
298+
let (neg, pos) = IArith.div x y in
299+
let (r, ov) = norm ik (join_no_norm ik neg pos) in (* normal join drops overflow info *)
300+
if leq (of_int ik Ints_t.zero |> fst) (Some y) then
301+
(top_of ik, ov)
302+
else
303+
(r, ov)
305304

306305
let ne ik x y =
307306
match x, y with

src/cdomain/value/cdomains/int/intervalSetDomain.ml

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,12 @@ struct
173173
let binary_op_with_norm op (ik:ikind) (x: t) (y: t) : t*overflow_info = match x, y with
174174
| [], _ -> ([],{overflow=false; underflow=false})
175175
| _, [] -> ([],{overflow=false; underflow=false})
176-
| _, _ -> norm_intvs ik @@ List.concat_map (fun (x,y) -> [op x y]) (BatList.cartesian_product x y)
176+
| _, _ -> norm_intvs ik @@ List.map (fun (x,y) -> op x y) (BatList.cartesian_product x y)
177+
178+
let binary_op_concat_with_norm op (ik:ikind) (x: t) (y: t) : t*overflow_info = match x, y with
179+
| [], _ -> ([],{overflow=false; underflow=false})
180+
| _, [] -> ([],{overflow=false; underflow=false})
181+
| _, _ -> norm_intvs ik @@ List.concat_map (fun (x,y) -> op x y) (BatList.cartesian_product x y)
177182

178183
let binary_op_with_ovc (x: t) (y: t) op : t*overflow_info = match x, y with
179184
| [], _ -> ([],{overflow=false; underflow=false})
@@ -187,7 +192,7 @@ struct
187192

188193
let unary_op_with_norm op (ik:ikind) (x: t) = match x with
189194
| [] -> ([],{overflow=false; underflow=false})
190-
| _ -> norm_intvs ik @@ List.concat_map (fun x -> [op x]) x
195+
| _ -> norm_intvs ik @@ List.map op x
191196

192197
let rec leq (xs: t) (ys: t) =
193198
let leq_interval (al, au) (bl, bu) = al >=. bl && au <=. bu in
@@ -358,17 +363,15 @@ struct
358363
let neg ?no_ov = unary_op_with_norm IArith.neg
359364

360365
let div ?no_ov ik x y =
361-
let rec interval_div x (y1, y2) = begin
362-
let top_of ik = top_of ik |> List.hd in
363-
let is_zero v = v =. Ints_t.zero in
364-
match y1, y2 with
365-
| l, u when is_zero l && is_zero u -> top_of ik
366-
| l, _ when is_zero l -> interval_div x (Ints_t.one,y2)
367-
| _, u when is_zero u -> interval_div x (y1, Ints_t.(neg one))
368-
| _ when leq (of_int ik (Ints_t.zero) |> fst) ([(y1,y2)]) -> top_of ik
369-
| _ -> IArith.div x (y1, y2)
370-
end
371-
in binary_op_with_norm interval_div ik x y
366+
let rec interval_div x y =
367+
let (neg, pos) = IArith.div x y in
368+
let r = List.filter_map Fun.id [neg; pos] in
369+
if leq (of_int ik Ints_t.zero |> fst) [y] then
370+
top_of ik @ r (* keep r because they might overflow, but top doesn't *)
371+
else
372+
r (* should always be singleton, because if there's a negative and a positive side, then it must've included zero, which is already handled by previous case *)
373+
in
374+
binary_op_concat_with_norm interval_div ik x y
372375

373376
let rem ik x y =
374377
let interval_rem (x, y) =

src/cdomain/value/cdomains/intDomain0.ml

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -361,16 +361,28 @@ module IntervalArith (Ints_t : IntOps.IntOps) = struct
361361
let y2p = Ints_t.shift_left Ints_t.one y2 in
362362
mul (x1, x2) (y1p, y2p)
363363

364-
let div (x1, x2) (y1, y2) =
365-
let x1y1n = (Ints_t.div x1 y1) in
366-
let x1y2n = (Ints_t.div x1 y2) in
367-
let x2y1n = (Ints_t.div x2 y1) in
368-
let x2y2n = (Ints_t.div x2 y2) in
369-
let x1y1p = (Ints_t.div x1 y1) in
370-
let x1y2p = (Ints_t.div x1 y2) in
371-
let x2y1p = (Ints_t.div x2 y1) in
372-
let x2y2p = (Ints_t.div x2 y2) in
373-
(min4 x1y1n x1y2n x2y1n x2y2n, max4 x1y1p x1y2p x2y1p x2y2p)
364+
(** Divide mathematical intervals.
365+
Excludes 0 from denominator - must be handled as desired by caller.
366+
367+
@return negative and positive denominator cases separately, if they exist.
368+
369+
@see <https://mine.perso.lip6.fr/publi/article-mine-FTiPL17.pdf> Miné, A. Tutorial on Static Inference of Numeric Invariants by Abstract Interpretation. Figure 4.6. *)
370+
let div (a, b) (c, d) =
371+
let pos =
372+
if Ints_t.(compare one d) <= 0 then
373+
let c = Ints_t.(max one c) in
374+
Some (Ints_t.(min (div a c) (div a d), max (div b c) (div b d)))
375+
else
376+
None
377+
in
378+
let neg =
379+
if Ints_t.(compare c zero) < 0 then
380+
let d = Ints_t.(min d (neg one)) in
381+
Some (Ints_t.(min (div b c) (div b d), max (div a c) (div a d)))
382+
else
383+
None
384+
in
385+
(neg, pos)
374386

375387
let add (x1, x2) (y1, y2) = (Ints_t.add x1 y1, Ints_t.add x2 y2)
376388
let sub (x1, x2) (y1, y2) = (Ints_t.sub x1 y2, Ints_t.sub x2 y1)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// PARAM: --enable ana.int.interval
2+
#include <limits.h>
3+
4+
int main() {
5+
int bad = INT_MIN / -1; // WARN (overflow)
6+
int x, y;
7+
bad = x / y; // WARN (div by zero and overflow, distinguished in cram test)
8+
if (y != 0) {
9+
bad = x / y; // WARN (overflow)
10+
}
11+
return 0;
12+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
$ goblint --enable warn.deterministic --enable ana.int.interval 15-div-minus-1.c
2+
[Warning][Integer > Overflow][CWE-190] Signed integer overflow (15-div-minus-1.c:5:9-5:26)
3+
[Warning][Integer > Overflow][CWE-190] Signed integer overflow (15-div-minus-1.c:7:5-7:16)
4+
[Warning][Integer > Overflow][CWE-190] Signed integer overflow (15-div-minus-1.c:9:9-9:20)
5+
[Warning][Integer > DivByZero][CWE-369] Second argument of division might be zero (15-div-minus-1.c:7:5-7:16)
6+
[Info][Deadcode] Logical lines of code (LLoC) summary:
7+
live: 6
8+
dead: 0
9+
total lines: 6
10+
11+
$ goblint --enable warn.deterministic --enable ana.int.interval_set 15-div-minus-1.c
12+
[Warning][Integer > Overflow][CWE-190] Signed integer overflow (15-div-minus-1.c:5:9-5:26)
13+
[Warning][Integer > Overflow][CWE-190] Signed integer overflow (15-div-minus-1.c:7:5-7:16)
14+
[Warning][Integer > Overflow][CWE-190] Signed integer overflow (15-div-minus-1.c:9:9-9:20)
15+
[Warning][Integer > DivByZero][CWE-369] Second argument of division might be zero (15-div-minus-1.c:7:5-7:16)
16+
[Info][Deadcode] Logical lines of code (LLoC) summary:
17+
live: 6
18+
dead: 0
19+
total lines: 6
20+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
(cram
2+
(deps (glob_files *.c)))

0 commit comments

Comments
 (0)