Skip to content

Commit

Permalink
Handle bitand in intervals and def_exc; Add test
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-schwarz committed Sep 10, 2023
1 parent 0193efa commit 526e8e4
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 9 deletions.
26 changes: 19 additions & 7 deletions src/analyses/baseInvariant.ml
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,18 @@ struct
meet_bin c c
else
a, b
| BAnd as op ->
(* we only attempt to refine a here *)
let a =
match ID.to_int b with
| Some x when BI.equal x BI.one ->
(match ID.to_bool c with
| Some true -> ID.meet a (ID.of_congruence ikind (Z.one, Z.of_int 2))
| Some false -> ID.meet a (ID.of_congruence ikind (Z.zero, Z.of_int 2))
| None -> if M.tracing then M.tracel "inv" "Unhandled case for operator x %a 1 = %a\n" d_binop op ID.pretty c; a)
| _ -> if M.tracing then M.tracel "inv" "Unhandled case for operator x %a %a = %a\n" d_binop op ID.pretty b ID.pretty c; a
in
a, b
| op ->
if M.tracing then M.tracel "inv" "Unhandled operator %a\n" d_binop op;
a, b
Expand Down Expand Up @@ -545,8 +557,8 @@ struct
in
let eval e st = eval_rv a gs st e in
let eval_bool e st = match eval e st with Int i -> ID.to_bool i | _ -> None in
let unroll_fk_of_exp e =
match unrollType (Cilfacade.typeOf e) with
let unroll_fk_of_exp e =
match unrollType (Cilfacade.typeOf e) with
| TFloat (fk, _) -> fk
| _ -> failwith "value which was expected to be a float is of different type?!"
in
Expand Down Expand Up @@ -700,8 +712,8 @@ struct
begin match t with
| TInt (ik, _) ->
begin match x with
| ((Var v), offs) ->
if M.tracing then M.trace "invSpecial" "qry Result: %a\n" Queries.ML.pretty (ctx.ask (Queries.TmpSpecial (v, Offset.Exp.of_cil offs)));
| ((Var v), offs) ->
if M.tracing then M.trace "invSpecial" "qry Result: %a\n" Queries.ML.pretty (ctx.ask (Queries.TmpSpecial (v, Offset.Exp.of_cil offs)));
let tv_opt = ID.to_bool c in
begin match tv_opt with
| Some tv ->
Expand Down Expand Up @@ -735,12 +747,12 @@ struct
begin match t with
| TFloat (fk, _) ->
begin match x with
| ((Var v), offs) ->
if M.tracing then M.trace "invSpecial" "qry Result: %a\n" Queries.ML.pretty (ctx.ask (Queries.TmpSpecial (v, Offset.Exp.of_cil offs)));
| ((Var v), offs) ->
if M.tracing then M.trace "invSpecial" "qry Result: %a\n" Queries.ML.pretty (ctx.ask (Queries.TmpSpecial (v, Offset.Exp.of_cil offs)));
begin match ctx.ask (Queries.TmpSpecial (v, Offset.Exp.of_cil offs)) with
| `Lifted (Ceil (ret_fk, xFloat)) -> inv_exp (Float (FD.inv_ceil (FD.cast_to ret_fk c))) xFloat st
| `Lifted (Floor (ret_fk, xFloat)) -> inv_exp (Float (FD.inv_floor (FD.cast_to ret_fk c))) xFloat st
| `Lifted (Fabs (ret_fk, xFloat)) ->
| `Lifted (Fabs (ret_fk, xFloat)) ->
let inv = FD.inv_fabs (FD.cast_to ret_fk c) in
if FD.is_bot inv then
raise Analyses.Deadcode
Expand Down
36 changes: 34 additions & 2 deletions src/cdomains/intDomain.ml
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,18 @@ struct
| _ -> (top_of ik,{underflow=true; overflow=true})

let bitxor = bit (fun _ik -> Ints_t.bitxor)
let bitand = bit (fun _ik -> Ints_t.bitand)

let bitand ik i1 i2 =
match is_bot i1, is_bot i2 with
| true, true -> bot_of ik
| true, _
| _ , true -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show i1) (show i2)))
| _ ->
match to_int i1, to_int i2 with
| Some x, Some y -> (try of_int ik (Ints_t.bitand x y) |> fst with Division_by_zero -> top_of ik)
| _, Some y when Ints_t.equal y Ints_t.one -> of_interval ik (Ints_t.zero, Ints_t.one) |> fst
| _ -> top_of ik

let bitor = bit (fun _ik -> Ints_t.bitor)

let bit1 f ik i1 =
Expand Down Expand Up @@ -2282,7 +2293,28 @@ struct
let ge ik x y = le ik y x

let bitnot = lift1 BigInt.bitnot
let bitand = lift2 BigInt.bitand

let bitand ik x y = norm ik (match x,y with
(* We don't bother with exclusion sets: *)
| `Excluded _, `Definite i ->
(* Except in two special cases *)
if BigInt.equal i BigInt.zero then
`Definite BigInt.zero
else if BigInt.equal i BigInt.one then
of_interval IBool (BigInt.zero, BigInt.one)
else
top ()
| `Definite _, `Excluded _
| `Excluded _, `Excluded _ -> top ()
(* The good case: *)
| `Definite x, `Definite y ->
(try `Definite (BigInt.bitand x y) with | Division_by_zero -> top ())
| `Bot, `Bot -> `Bot
| _ ->
(* If only one of them is bottom, we raise an exception that eval_rv will catch *)
raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y))))


let bitor = lift2 BigInt.bitor
let bitxor = lift2 BigInt.bitxor

Expand Down
41 changes: 41 additions & 0 deletions tests/regression/37-congruence/13-bitand.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// PARAM: --enable ana.int.congruence --set sem.int.signed_overflow assume_none
#include <goblint.h>

int main()
{
// Assuming modulo expression

long x;
__goblint_assume(x % 2 == 1);
__goblint_check(x % 2 == 1);
__goblint_check(x & 1);

long y;
__goblint_assume(y % 2 == 0);
__goblint_check(y % 2 == 0);
__goblint_check(y & 1); //FAIL

long z;
__goblint_check(z & 1); //UNKNOWN!
__goblint_assume(z % 8 == 1);
__goblint_check(z & 1);

long xz;
__goblint_assume(xz % 3 == 1);
__goblint_check(xz & 1); //UNKNOWN!
__goblint_assume(xz % 6 == 1);
__goblint_check(xz & 1);

// Assuming bitwise expression

// For some reason does not work for longs yet
long a;
__goblint_assume(a & 1);
__goblint_check(a % 2 == 1);
__goblint_check(a & 1);

int b;
__goblint_assume(b & 1);
__goblint_check(b % 2 == 1);
__goblint_check(b & 1);
}

0 comments on commit 526e8e4

Please sign in to comment.