From af781ed684c538cfa98ef0d35a9d258fec62e495 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 12:56:40 +0300 Subject: [PATCH 1/8] Enable ana.float.evaluate_math_functions in svcomp24 and svcomp confs This is needed for sv-benchmarks Juliet no-overflow tasks involving sqrt. We used this at SV-COMP 2024, before the option existed. --- conf/svcomp.json | 3 ++- conf/svcomp24-validate.json | 3 ++- conf/svcomp24.json | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/conf/svcomp.json b/conf/svcomp.json index 467d294bdd..d2bea96040 100644 --- a/conf/svcomp.json +++ b/conf/svcomp.json @@ -10,7 +10,8 @@ "interval": true }, "float": { - "interval": true + "interval": true, + "evaluate_math_functions": true }, "activated": [ "base", diff --git a/conf/svcomp24-validate.json b/conf/svcomp24-validate.json index 7832ffa6af..d83b1767a4 100644 --- a/conf/svcomp24-validate.json +++ b/conf/svcomp24-validate.json @@ -10,7 +10,8 @@ "interval": true }, "float": { - "interval": true + "interval": true, + "evaluate_math_functions": true }, "activated": [ "base", diff --git a/conf/svcomp24.json b/conf/svcomp24.json index 7e30554ceb..1c60f84920 100644 --- a/conf/svcomp24.json +++ b/conf/svcomp24.json @@ -10,7 +10,8 @@ "interval": true }, "float": { - "interval": true + "interval": true, + "evaluate_math_functions": true }, "activated": [ "base", From 3ff00aea295c6e7386323efc88f38d1a046cbdbc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 13:00:36 +0300 Subject: [PATCH 2/8] Add tests for imaxabs --- .../39-signed-overflows/11-imaxabs.c | 24 +++++++++++++++++++ .../39-signed-overflows/12-imaxabs-sqrt.c | 12 ++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/regression/39-signed-overflows/11-imaxabs.c create mode 100644 tests/regression/39-signed-overflows/12-imaxabs-sqrt.c diff --git a/tests/regression/39-signed-overflows/11-imaxabs.c b/tests/regression/39-signed-overflows/11-imaxabs.c new file mode 100644 index 0000000000..dce200a146 --- /dev/null +++ b/tests/regression/39-signed-overflows/11-imaxabs.c @@ -0,0 +1,24 @@ +//PARAM: --enable ana.int.interval --set ana.activated[+] tmpSpecial +#include +#include +#include +int main() { + int64_t data; + if (data > (-0x7fffffffffffffff - 1)) + { + if (imaxabs(data) < 100) + { + __goblint_check(data < 100); // TODO + __goblint_check(-100 < data); // TODO + int64_t result = data * data; // TODO NOWARN + } + + if(imaxabs(data) <= 100) + { + __goblint_check(data <= 100); // TODO + __goblint_check(-100 <= data); // TODO + int64_t result = data * data; // TODO NOWARN + } + } + return 8; +} diff --git a/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c new file mode 100644 index 0000000000..b121645b27 --- /dev/null +++ b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c @@ -0,0 +1,12 @@ +//PARAM: --enable ana.int.interval --enable ana.float.interval --enable ana.float.evaluate_math_functions --set ana.activated[+] tmpSpecial +#include +#include +#include +int main() { + int64_t data; + if (data > (-0x7fffffffffffffff - 1) && imaxabs((intmax_t)data) <= sqrtl(0x7fffffffffffffffLL)) + { + int64_t result = data * data; // TODO NOWARN + } + return 8; +} From 2653e2ea22dd9d012a10e008f3189e1061d2c344 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 13:02:26 +0300 Subject: [PATCH 3/8] Add hacky imaxabs support --- src/util/library/libraryFunctions.ml | 2 +- tests/regression/39-signed-overflows/11-imaxabs.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index e7ff2a4d04..df90339c65 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -139,7 +139,7 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("abs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (IInt, j)) }); ("labs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILong, j)) }); ("llabs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILongLong, j)) }); - ("imaxabs", unknown [drop "j" []]); + ("imaxabs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILong, j)) }); (* TODO: look up intmax_t ikind from CIL file *) ("localtime_r", unknown [drop "timep" [r]; drop "result" [w]]); ("strpbrk", unknown [drop "s" [r]; drop "accept" [r]]); ("_setjmp", special [__ "env" [w]] @@ fun env -> Setjmp { env }); (* only has one underscore *) diff --git a/tests/regression/39-signed-overflows/11-imaxabs.c b/tests/regression/39-signed-overflows/11-imaxabs.c index dce200a146..47bd26569f 100644 --- a/tests/regression/39-signed-overflows/11-imaxabs.c +++ b/tests/regression/39-signed-overflows/11-imaxabs.c @@ -8,16 +8,16 @@ int main() { { if (imaxabs(data) < 100) { - __goblint_check(data < 100); // TODO - __goblint_check(-100 < data); // TODO - int64_t result = data * data; // TODO NOWARN + __goblint_check(data < 100); + __goblint_check(-100 < data); + int64_t result = data * data; // NOWARN } if(imaxabs(data) <= 100) { - __goblint_check(data <= 100); // TODO - __goblint_check(-100 <= data); // TODO - int64_t result = data * data; // TODO NOWARN + __goblint_check(data <= 100); + __goblint_check(-100 <= data); + int64_t result = data * data; // NOWARN } } return 8; From f9765da81d64a99f77c385835c6c0a5c3db419da Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 13:05:26 +0300 Subject: [PATCH 4/8] Add hacky imaxabs sqrt refine support --- src/analyses/baseInvariant.ml | 3 ++- tests/regression/39-signed-overflows/12-imaxabs-sqrt.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/analyses/baseInvariant.ml b/src/analyses/baseInvariant.ml index 51a27e19f8..d5b65a95f4 100644 --- a/src/analyses/baseInvariant.ml +++ b/src/analyses/baseInvariant.ml @@ -785,7 +785,8 @@ struct | TFloat (fk, _), FLongDouble | TFloat (FDouble as fk, _), FDouble | TFloat (FFloat as fk, _), FFloat -> inv_exp (Float (FD.cast_to fk c)) e st - | _ -> fallback (fun () -> Pretty.text "CastE: incompatible types") st) + | TInt (ik, _), _ -> inv_exp (Int (FD.to_int ik c)) e st (* TODO: is this cast refinement correct? *) + | t, fk -> fallback (fun () -> Pretty.dprintf "CastE: incompatible types %a and %a" CilType.Typ.pretty t CilType.Fkind.pretty fk) st) | CastE ((TInt (ik, _)) as t, e), Int c | CastE ((TEnum ({ekind = ik; _ }, _)) as t, e), Int c -> (* Can only meet the t part of an Lval in e with c (unless we meet with all overflow possibilities)! Since there is no good way to do this, we only continue if e has no values outside of t. *) (match eval e st with diff --git a/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c index b121645b27..46512aed21 100644 --- a/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c +++ b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c @@ -6,7 +6,7 @@ int main() { int64_t data; if (data > (-0x7fffffffffffffff - 1) && imaxabs((intmax_t)data) <= sqrtl(0x7fffffffffffffffLL)) { - int64_t result = data * data; // TODO NOWARN + int64_t result = data * data; // NOWARN } return 8; } From a1f0b35703e34da0eda8f3f27ea260a58fd2c85d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 20 Jun 2024 13:15:01 +0300 Subject: [PATCH 5/8] Find intmax_t for imaxabs from program --- src/util/library/libraryFunctions.ml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index df90339c65..689eb17126 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -6,6 +6,16 @@ open GobConfig module M = Messages +let intmax_t = lazy ( + let res = ref None in + GoblintCil.iterGlobals !Cilfacade.current_file (function + | GType ({tname = "intmax_t"; ttype; _}, _) -> + res := Some ttype; + | _ -> () + ); + !res +) + (** C standard library functions. These are specified by the C standard. *) let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ @@ -139,7 +149,7 @@ let c_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("abs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (IInt, j)) }); ("labs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILong, j)) }); ("llabs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILongLong, j)) }); - ("imaxabs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (ILong, j)) }); (* TODO: look up intmax_t ikind from CIL file *) + ("imaxabs", special [__ "j" []] @@ fun j -> Math { fun_args = (Abs (Cilfacade.get_ikind (Option.get (Lazy.force intmax_t)), j)) }); ("localtime_r", unknown [drop "timep" [r]; drop "result" [w]]); ("strpbrk", unknown [drop "s" [r]; drop "accept" [r]]); ("_setjmp", special [__ "env" [w]] @@ fun env -> Setjmp { env }); (* only has one underscore *) From 2f5b50fa9081abda073a33b393ef33c282c1ebc4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 16 Oct 2024 16:51:40 +0300 Subject: [PATCH 6/8] Revert "Add hacky imaxabs sqrt refine support" This reverts commit f9765da81d64a99f77c385835c6c0a5c3db419da. --- src/analyses/baseInvariant.ml | 3 +-- tests/regression/39-signed-overflows/12-imaxabs-sqrt.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/analyses/baseInvariant.ml b/src/analyses/baseInvariant.ml index d5b65a95f4..51a27e19f8 100644 --- a/src/analyses/baseInvariant.ml +++ b/src/analyses/baseInvariant.ml @@ -785,8 +785,7 @@ struct | TFloat (fk, _), FLongDouble | TFloat (FDouble as fk, _), FDouble | TFloat (FFloat as fk, _), FFloat -> inv_exp (Float (FD.cast_to fk c)) e st - | TInt (ik, _), _ -> inv_exp (Int (FD.to_int ik c)) e st (* TODO: is this cast refinement correct? *) - | t, fk -> fallback (fun () -> Pretty.dprintf "CastE: incompatible types %a and %a" CilType.Typ.pretty t CilType.Fkind.pretty fk) st) + | _ -> fallback (fun () -> Pretty.text "CastE: incompatible types") st) | CastE ((TInt (ik, _)) as t, e), Int c | CastE ((TEnum ({ekind = ik; _ }, _)) as t, e), Int c -> (* Can only meet the t part of an Lval in e with c (unless we meet with all overflow possibilities)! Since there is no good way to do this, we only continue if e has no values outside of t. *) (match eval e st with diff --git a/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c index 46512aed21..b121645b27 100644 --- a/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c +++ b/tests/regression/39-signed-overflows/12-imaxabs-sqrt.c @@ -6,7 +6,7 @@ int main() { int64_t data; if (data > (-0x7fffffffffffffff - 1) && imaxabs((intmax_t)data) <= sqrtl(0x7fffffffffffffffLL)) { - int64_t result = data * data; // NOWARN + int64_t result = data * data; // TODO NOWARN } return 8; } From f7a5afa966d6dc4b62748fdb1738f2b2aef2f844 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 16 Oct 2024 17:39:07 +0300 Subject: [PATCH 7/8] Add 39-signed-overflows/13-imaxabs-macos test --- .../39-signed-overflows/13-imaxabs-macos.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/regression/39-signed-overflows/13-imaxabs-macos.c diff --git a/tests/regression/39-signed-overflows/13-imaxabs-macos.c b/tests/regression/39-signed-overflows/13-imaxabs-macos.c new file mode 100644 index 0000000000..745d5b74c4 --- /dev/null +++ b/tests/regression/39-signed-overflows/13-imaxabs-macos.c @@ -0,0 +1,25 @@ +//PARAM: --enable ana.int.interval --set ana.activated[+] tmpSpecial +// 39-signed-overflows/11-imaxabs, but with long long as int64_t instead (https://github.com/goblint/analyzer/pull/1519#issuecomment-2417032186). +#include +#include +#include +int main() { + long long data; + if (data > (-0x7fffffffffffffff - 1)) + { + if (imaxabs(data) < 100) + { + __goblint_check(data < 100); + __goblint_check(-100 < data); + long long result = data * data; // NOWARN + } + + if(imaxabs(data) <= 100) + { + __goblint_check(data <= 100); + __goblint_check(-100 <= data); + long long result = data * data; // NOWARN + } + } + return 8; +} From 62834684764e5e1bc88705f19c54fa22a0d35d64 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 16 Oct 2024 17:55:20 +0300 Subject: [PATCH 8/8] Unroll cast type in BaseInvariant --- src/analyses/baseInvariant.ml | 58 +++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/src/analyses/baseInvariant.ml b/src/analyses/baseInvariant.ml index 51a27e19f8..52f0888d3f 100644 --- a/src/analyses/baseInvariant.ml +++ b/src/analyses/baseInvariant.ml @@ -777,33 +777,37 @@ struct | _ -> assert false end | Const _ , _ -> st (* nothing to do *) - | CastE ((TFloat (_, _)), e), Float c -> - (match unrollType (Cilfacade.typeOf e), FD.get_fkind c with - | TFloat (FLongDouble as fk, _), FFloat - | TFloat (FDouble as fk, _), FFloat - | TFloat (FLongDouble as fk, _), FDouble - | TFloat (fk, _), FLongDouble - | TFloat (FDouble as fk, _), FDouble - | TFloat (FFloat as fk, _), FFloat -> inv_exp (Float (FD.cast_to fk c)) e st - | _ -> fallback (fun () -> Pretty.text "CastE: incompatible types") st) - | CastE ((TInt (ik, _)) as t, e), Int c - | CastE ((TEnum ({ekind = ik; _ }, _)) as t, e), Int c -> (* Can only meet the t part of an Lval in e with c (unless we meet with all overflow possibilities)! Since there is no good way to do this, we only continue if e has no values outside of t. *) - (match eval e st with - | Int i -> - (match unrollType (Cilfacade.typeOf e) with - | (TInt(ik_e, _) as t') - | (TEnum ({ekind = ik_e; _ }, _) as t') -> - if VD.is_dynamically_safe_cast t t' (Int i) then - (* let c' = ID.cast_to ik_e c in *) - (* Suppressing overflow warnings as this is not a computation that comes from the program *) - let res_range = (ID.cast_to ~suppress_ovwarn:true ik (ID.top_of ik_e)) in - let c' = ID.cast_to ik_e (ID.meet c res_range) in (* TODO: cast without overflow, is this right for normal invariant? *) - if M.tracing then M.tracel "inv" "cast: %a from %a to %a: i = %a; cast c = %a to %a = %a" d_exp e d_ikind ik_e d_ikind ik ID.pretty i ID.pretty c d_ikind ik_e ID.pretty c'; - inv_exp (Int c') e st - else - fallback (fun () -> Pretty.dprintf "CastE: %a evaluates to %a which is bigger than the type it is cast to which is %a" d_plainexp e ID.pretty i CilType.Typ.pretty t) st - | x -> fallback (fun () -> Pretty.dprintf "CastE: e did evaluate to Int, but the type did not match %a" CilType.Typ.pretty t) st) - | v -> fallback (fun () -> Pretty.dprintf "CastE: e did not evaluate to Int, but %a" VD.pretty v) st) + | CastE (t, e), c_typed -> + begin match Cil.unrollType t, c_typed with + | TFloat (_, _), Float c -> + (match unrollType (Cilfacade.typeOf e), FD.get_fkind c with + | TFloat (FLongDouble as fk, _), FFloat + | TFloat (FDouble as fk, _), FFloat + | TFloat (FLongDouble as fk, _), FDouble + | TFloat (fk, _), FLongDouble + | TFloat (FDouble as fk, _), FDouble + | TFloat (FFloat as fk, _), FFloat -> inv_exp (Float (FD.cast_to fk c)) e st + | _ -> fallback (fun () -> Pretty.text "CastE: incompatible types") st) + | (TInt (ik, _) as t), Int c + | (TEnum ({ekind = ik; _ }, _) as t), Int c -> (* Can only meet the t part of an Lval in e with c (unless we meet with all overflow possibilities)! Since there is no good way to do this, we only continue if e has no values outside of t. *) + (match eval e st with + | Int i -> + (match unrollType (Cilfacade.typeOf e) with + | (TInt(ik_e, _) as t') + | (TEnum ({ekind = ik_e; _ }, _) as t') -> + if VD.is_dynamically_safe_cast t t' (Int i) then + (* let c' = ID.cast_to ik_e c in *) + (* Suppressing overflow warnings as this is not a computation that comes from the program *) + let res_range = (ID.cast_to ~suppress_ovwarn:true ik (ID.top_of ik_e)) in + let c' = ID.cast_to ik_e (ID.meet c res_range) in (* TODO: cast without overflow, is this right for normal invariant? *) + if M.tracing then M.tracel "inv" "cast: %a from %a to %a: i = %a; cast c = %a to %a = %a" d_exp e d_ikind ik_e d_ikind ik ID.pretty i ID.pretty c d_ikind ik_e ID.pretty c'; + inv_exp (Int c') e st + else + fallback (fun () -> Pretty.dprintf "CastE: %a evaluates to %a which is bigger than the type it is cast to which is %a" d_plainexp e ID.pretty i CilType.Typ.pretty t) st + | x -> fallback (fun () -> Pretty.dprintf "CastE: e did evaluate to Int, but the type did not match %a" CilType.Typ.pretty t) st) + | v -> fallback (fun () -> Pretty.dprintf "CastE: e did not evaluate to Int, but %a" VD.pretty v) st) + | _, _ -> fallback (fun () -> Pretty.dprintf "CastE: %a not implemented" d_plainexp (CastE (t, e))) st + end | e, _ -> fallback (fun () -> Pretty.dprintf "%a not implemented" d_plainexp e) st in if eval_bool exp st = Some (not tv) then contra st (* we already know that the branch is dead *)