2024-05-29 11:47:47 +02:00
|
|
|
(*
|
|
|
|
Cours "Sémantique et Application à la Vérification de programmes"
|
|
|
|
|
|
|
|
Antoine Miné 2015
|
|
|
|
Marc Chevalier 2018
|
|
|
|
Josselin Giet 2021
|
|
|
|
Ecole normale supérieure, Paris, France / CNRS / INRIA
|
|
|
|
*)
|
|
|
|
|
|
|
|
open Cfg
|
2024-06-08 21:54:06 +02:00
|
|
|
open Iterable
|
2024-05-29 11:47:47 +02:00
|
|
|
|
|
|
|
let pp_asserts out a =
|
|
|
|
ArcSet.iter (fun arc -> match arc.arc_inst with
|
|
|
|
| CFG_assert (b, ext) -> Format.fprintf out "%a@ " Errors.pp_err (AssertFalse, ext, b)
|
|
|
|
| _ -> failwith "Failed on non-assert") a
|
|
|
|
|
2024-06-08 21:54:06 +02:00
|
|
|
|
|
|
|
module Iterator (I : ITERABLE) = struct
|
2024-05-29 11:47:47 +02:00
|
|
|
|
2024-05-29 22:30:48 +02:00
|
|
|
(*let pp_nodes out (s,nodelist) =
|
2024-05-29 11:47:47 +02:00
|
|
|
List.iter (fun node -> (Format.fprintf out "<%i>: %a@ " node.node_id D.print (node_abst node s))) nodelist
|
2024-05-29 22:30:48 +02:00
|
|
|
*)
|
2024-05-29 11:47:47 +02:00
|
|
|
let iterate cfg =
|
|
|
|
let failed_asserts = ref ArcSet.empty in
|
2024-05-29 22:30:48 +02:00
|
|
|
|
2024-06-08 21:54:06 +02:00
|
|
|
let rec do_fun (f : func) (ctx : I.t) = (*returns an abstraction of the result of exec*)
|
2024-05-29 22:30:48 +02:00
|
|
|
let func_state = ref NodeMap.empty in (*avoid losing precision between function calls*)
|
|
|
|
let func_dirty = ref NodeSet.empty in begin
|
|
|
|
func_state := NodeMap.add f.func_entry ctx (!func_state);
|
2024-05-29 11:47:47 +02:00
|
|
|
|
2024-06-08 21:54:06 +02:00
|
|
|
let node_abst n = try( NodeMap.find n !func_state )with Not_found -> I.bottom in
|
|
|
|
|
2024-05-29 22:30:48 +02:00
|
|
|
let rec iterate n = begin
|
2024-06-01 19:29:10 +02:00
|
|
|
(*Format.printf "@[<h 0> Handling node %i@]@ " n.node_id;*)
|
2024-05-29 22:30:48 +02:00
|
|
|
func_dirty := NodeSet.remove n !func_dirty;
|
|
|
|
let curr_abst = node_abst n in
|
2024-06-08 21:54:06 +02:00
|
|
|
List.iter (fun arc ->
|
|
|
|
let nv = I.do_compute arc curr_abst
|
|
|
|
(fun a -> failed_asserts := ArcSet.add a !failed_asserts)
|
|
|
|
do_fun in
|
|
|
|
let s,b = I.accumulate arc (node_abst arc.arc_dst) nv in
|
|
|
|
func_state := NodeMap.add arc.arc_dst s !func_state;
|
|
|
|
if b then func_dirty := NodeSet.add arc.arc_dst !func_dirty;) n.node_out;
|
2024-05-29 22:30:48 +02:00
|
|
|
if NodeSet.is_empty !func_dirty then () else
|
|
|
|
iterate (NodeSet.choose !func_dirty)
|
2024-06-08 21:54:06 +02:00
|
|
|
end in
|
2024-05-29 22:30:48 +02:00
|
|
|
iterate f.func_entry;
|
|
|
|
node_abst f.func_exit;
|
|
|
|
end
|
|
|
|
in
|
2024-05-29 11:47:47 +02:00
|
|
|
begin
|
|
|
|
Format.printf "@[<v 0>";
|
2024-05-29 22:30:48 +02:00
|
|
|
let init_st = do_fun {func_id = -1; func_name = "_init";
|
|
|
|
func_pos = Lexing.dummy_pos, Lexing.dummy_pos;
|
|
|
|
func_entry = cfg.cfg_init_entry;
|
|
|
|
func_exit = cfg.cfg_init_exit;
|
|
|
|
func_args = [];
|
|
|
|
func_ret = None;
|
2024-06-08 21:54:06 +02:00
|
|
|
func_calls = []} I.init in
|
2024-06-01 19:29:10 +02:00
|
|
|
let rec do_main l = match l with
|
|
|
|
| x::_ when x.func_name = "main" -> do_fun x init_st
|
|
|
|
| _::q -> do_main q
|
|
|
|
| [] -> failwith "function main() not found" in
|
|
|
|
let _ = do_main cfg.cfg_funcs in
|
2024-05-29 11:47:47 +02:00
|
|
|
Format.printf "@]";
|
2024-05-29 22:30:48 +02:00
|
|
|
!failed_asserts
|
2024-05-29 11:47:47 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-06-01 20:58:56 +02:00
|
|
|
open Interval
|
2024-05-29 11:47:47 +02:00
|
|
|
open Sign
|
|
|
|
open Constant
|
|
|
|
open Naked
|
|
|
|
open Value_domain
|
2024-06-08 10:48:13 +02:00
|
|
|
open Congruence
|
|
|
|
open Reduced_product
|
|
|
|
|
|
|
|
module IntervalxCongr : CROSS_REDUCTION = struct
|
|
|
|
module V = AddTopBot(Interval)
|
|
|
|
module W = AddTopBot(Congruence)
|
|
|
|
let cr (v,w) = match v,w with
|
|
|
|
| _, W.Bot | V.Bot, _ -> V.Bot, W.Bot
|
|
|
|
| V.Top, _ | _, W.Top -> v,w
|
|
|
|
| V.V i, W.V c -> match c.multiple with
|
|
|
|
| m when Z.equal Z.zero m -> if Z.leq i.lower c.offset && Z.leq c.offset i.upper then
|
|
|
|
V.V {lower=c.offset; upper=c.offset}, w
|
|
|
|
else
|
|
|
|
V.Bot, W.Bot
|
|
|
|
| m -> (* Non-trivial multiplier : can only hope refining the bounds *)
|
|
|
|
let q = Z.div (Z.sub i.upper c.offset) m in (*rounds towards zero*)
|
|
|
|
let q' = Z.div (Z.sub i.lower c.offset) m in
|
|
|
|
if Z.equal q' q then
|
|
|
|
let z = Z.add c.offset (Z.mul q' m) in
|
|
|
|
let newint = V.const z and
|
|
|
|
newmod = W.const z in newint, newmod
|
|
|
|
else (if Z.leq q' q then
|
|
|
|
let newint = V.rand (Z.add c.offset (Z.mul q' m))
|
|
|
|
(Z.add c.offset (Z.mul q m)) in
|
|
|
|
newint, w
|
|
|
|
else
|
|
|
|
V.Bot, W.Bot)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2024-06-08 21:54:06 +02:00
|
|
|
module ConstIterator = Iterator(SimpleIterable(NonRelational(AddTopBot(Constants))))
|
|
|
|
module SignIterator = Iterator(SimpleIterable(NonRelational(AddTopBot(Signs))))
|
|
|
|
module IntervalIterator = Iterator(SimpleIterable(NonRelational(AddTopBot(Interval))))
|
|
|
|
module CongIterator = Iterator(SimpleIterable(NonRelational(AddTopBot(Congruence))))
|
|
|
|
module RPIterator = Iterator(SimpleIterable(NonRelational(ReducedProduct(IntervalxCongr))))
|
|
|
|
|
|
|
|
module ConstDisjIterator = Iterator(DisjunctiveIterable(NonRelational(AddTopBot(Constants))))
|
|
|
|
module SignDisjIterator = Iterator(DisjunctiveIterable(NonRelational(AddTopBot(Signs))))
|
|
|
|
module IntervalDisjIterator = Iterator(DisjunctiveIterable(NonRelational(AddTopBot(Interval))))
|
|
|
|
module CongDisjIterator = Iterator(DisjunctiveIterable(NonRelational(AddTopBot(Congruence))))
|
|
|
|
module RPDisjIterator = Iterator(DisjunctiveIterable(NonRelational(ReducedProduct(IntervalxCongr))))
|
|
|
|
|