Skip to content

Commit 0d03c9f

Browse files
authored
Merge pull request #1587 from goblint/congruence-hardness-unsound-branches
Unsound congruence domain arithmetic
2 parents 2c36291 + a1963da commit 0d03c9f

File tree

5 files changed

+126
-13
lines changed

5 files changed

+126
-13
lines changed

scripts/creduce/branches.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
gcc -c -Werror=implicit-function-declaration ./bad.c
6+
7+
GOBLINTDIR="/home/simmo/dev/goblint/sv-comp/goblint"
8+
OPTS="--conf $GOBLINTDIR/conf/svcomp.json --set ana.specification $GOBLINTDIR/../sv-benchmarks/c/properties/unreach-call.prp bad.c --enable pre.enabled"
9+
LOG="goblint.log"
10+
11+
$GOBLINTDIR/goblint $OPTS -v &> $LOG
12+
13+
grep -F "Both branches dead" $LOG

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

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -139,21 +139,21 @@ struct
139139

140140
let of_congruence ik (c,m) = normalize ik @@ Some(c,m)
141141

142-
let of_bitfield ik (z,o) =
142+
let of_bitfield ik (z,o) =
143143
match BitfieldDomain.Bitfield.to_int (z,o) with
144144
| Some x -> normalize ik (Some (x, Z.zero))
145145
| _ ->
146146
(* get posiiton of first top bit *)
147-
let tl_zeros = Z.trailing_zeros (Z.logand z o) in
148-
let ik_bits = Size.bit ik in
149-
let m = if tl_zeros > ik_bits then Z.one else Z.pow Z.one tl_zeros in
150-
let c = Z.logand o (m -: Z.one) in
147+
let tl_zeros = Z.trailing_zeros (Z.logand z o) in
148+
let ik_bits = Size.bit ik in
149+
let m = if tl_zeros > ik_bits then Z.one else Z.pow Z.one tl_zeros in
150+
let c = Z.logand o (m -: Z.one) in
151151
normalize ik (Some (c, m))
152152

153-
let to_bitfield ik x =
154-
let x = normalize ik x in
155-
match x with
156-
| None -> (Z.zero, Z.zero)
153+
let to_bitfield ik x =
154+
let x = normalize ik x in
155+
match x with
156+
| None -> (Z.zero, Z.zero)
157157
| Some (c,m) -> BitfieldDomain.Bitfield.of_congruence ik (c,m)
158158

159159
let maximal t = match t with
@@ -336,8 +336,32 @@ struct
336336
pretty res ;
337337
res
338338

339-
let sub ?(no_ov=false) ik x y = add ~no_ov ik x (neg ~no_ov ik y)
340-
339+
let sub ?(no_ov=false) ik x y =
340+
let no_ov_case (c1, m1) (c2, m2) =
341+
c1 -: c2, Z.gcd m1 m2
342+
in
343+
match (x, y) with
344+
| None, None -> bot ()
345+
| None, _
346+
| _, None ->
347+
raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))
348+
| Some a, Some b when no_ov ->
349+
normalize ik (Some (no_ov_case a b))
350+
| Some (c1, m1), Some (c2, m2) when m1 =: Z.zero && m2 =: Z.zero ->
351+
let min_ik, max_ik = range ik in
352+
let m_ikind = max_ik +: Z.one in
353+
if Cil.isSigned ik then
354+
let c = c1 -: c2 in
355+
if c >=: min_ik && c <= max_ik then
356+
Some (c, Z.zero)
357+
else
358+
top_of ik
359+
else
360+
let c = (c1 -: c2 +: m_ikind) %: m_ikind in
361+
Some (c, Z.zero)
362+
| Some a, Some b when not (Cil.isSigned ik) ->
363+
handle_overflow ik (no_ov_case a b)
364+
| _ -> top ()
341365

342366
let sub ?no_ov ik x y =
343367
let res = sub ?no_ov ik x y in
@@ -506,8 +530,8 @@ struct
506530

507531
let refine_with_congruence ik a b = meet ik a b
508532

509-
let refine_with_bitfield ik a (z,o) =
510-
let a = normalize ik a in
533+
let refine_with_bitfield ik a (z,o) =
534+
let a = normalize ik a in
511535
meet ik a (of_bitfield ik (z,o))
512536

513537
let refine_with_excl_list ik a b = a
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// PARAM: --enable ana.int.congruence --enable ana.int.interval
2+
// reduced (via creduce and manually) from sv-benchmarks/c/hardness-nfm22/hardness_codestructure_dependencies_file-70.c
3+
4+
#include <goblint.h>
5+
6+
main() {
7+
int a;
8+
unsigned c = 1;
9+
if (a)
10+
c = 4;
11+
12+
// The following condition evaluated to "both branches dead", due to a bug in the congruence domain.
13+
// --- Even though the condition is true the concrete.
14+
if (c + (c + 2))
15+
a = 1;
16+
17+
// Check that this is reachable.
18+
// That is, check that not both branches of previous condition are dead.
19+
__goblint_check(1);
20+
return 0;
21+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// PARAM: --enable ana.int.bitfield --enable ana.int.enums --enable ana.int.congruence --enable ana.int.interval --set ana.int.refinement fixpoint
2+
// FIXPOINT
3+
int main(void)
4+
{
5+
unsigned int c = 3;
6+
unsigned int d = 6;
7+
unsigned int e = 9;
8+
int burgo;
9+
10+
while (1) {
11+
c ++;
12+
13+
d += 2U;
14+
15+
e += 3U;
16+
// To produce the fixpoint not reached error, the following needed to be an assert:
17+
assert(e == (unsigned int )c + d); //UNKNOWN
18+
19+
burgo = 23;
20+
}
21+
22+
return (0);
23+
24+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// PARAM: --enable ana.int.congruence --disable ana.int.bitfield --disable ana.int.enums --disable ana.int.interval --disable ana.int.def_exc
2+
3+
#include<limits.h>
4+
#include<goblint.h>
5+
6+
int main(void)
7+
{
8+
unsigned x = 0;
9+
unsigned y = 1;
10+
11+
unsigned int z = x - y;
12+
__goblint_check(UINT_MAX == z);
13+
14+
int a = 1;
15+
int b = 2;
16+
17+
int c = a - b;
18+
19+
__goblint_check(c == -1);
20+
21+
int min = INT_MIN;
22+
int ov = min - 1;
23+
24+
__goblint_check(ov == INT_MAX); //UNKNOWN!
25+
26+
int ov2 = 0 - min;
27+
__goblint_check(ov2 == INT_MAX); //UNKNOWN!
28+
29+
return (0);
30+
31+
}

0 commit comments

Comments
 (0)