You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
3.9 KiB

(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
(** Relational abstract domain, elements of which are interpreted as Hoare
triples over a base state domain *)
module type State_domain_sig = sig
include Domain_intf.Dom
val create_summary :
locals:Reg.Set.t
-> formals:Reg.Set.t
-> entry:t
-> current:t
-> summary * t
end
module Make (State_domain : State_domain_sig) = struct
type t = State_domain.t * State_domain.t [@@deriving equal, sexp_of]
let embed b = (b, b)
let pp_entry fs entry =
[%Trace.fprintf fs "entry: %a@ current: " State_domain.pp entry]
let pp fs (entry, curr) =
Format.fprintf fs "@[%a%a@]" pp_entry entry State_domain.pp curr
let report_fmt_thunk (_, curr) fs = State_domain.pp fs curr
let init globals = embed (State_domain.init globals)
let join (entry_a, current_a) (entry_b, current_b) =
if State_domain.equal entry_a entry_b then
let+ next = State_domain.join current_a current_b in
(entry_a, next)
else None
let is_false (_, curr) = State_domain.is_false curr
let exec_assume (entry, current) cnd =
let+ next = State_domain.exec_assume current cnd in
(entry, next)
let exec_kill (entry, current) reg =
(entry, State_domain.exec_kill current reg)
let exec_move (entry, current) reg_exps =
(entry, State_domain.exec_move current reg_exps)
let exec_inst (entry, current) inst =
let+ next = State_domain.exec_inst current inst in
(entry, next)
let exec_intrinsic ~skip_throw (entry, current) areturn intrinsic actuals
=
let+ next_opt =
State_domain.exec_intrinsic ~skip_throw current areturn intrinsic
actuals
in
let+ next = next_opt in
(entry, next)
type from_call =
{state_from_call: State_domain.from_call; caller_entry: State_domain.t}
[@@deriving sexp_of]
let recursion_beyond_bound = State_domain.recursion_beyond_bound
let call ~summaries ~globals ~actuals ~areturn ~formals ~freturn ~locals
(entry, current) =
[%Trace.call fun {pf} ->
pf
"@[<v>@[actuals: (@[%a@])@ formals: (@[%a@])@]@ locals: {@[%a@]}@ \
globals: {@[%a@]}@ current: %a@]"
(List.pp ",@ " Exp.pp) (List.rev actuals) (List.pp ",@ " Reg.pp)
(List.rev formals) Reg.Set.pp locals Reg.Set.pp globals
State_domain.pp current]
;
let caller_current, state_from_call =
State_domain.call ~summaries ~globals ~actuals ~areturn ~formals
~freturn ~locals current
in
( (caller_current, caller_current)
, {state_from_call; caller_entry= entry} )
|>
[%Trace.retn fun {pf} (reln, _) -> pf "@,%a" pp reln]
let post locals {state_from_call; caller_entry} (_, current) =
[%Trace.call fun {pf} -> pf "locals: %a" Reg.Set.pp locals]
;
(caller_entry, State_domain.post locals state_from_call current)
|>
[%Trace.retn fun {pf} -> pf "@,%a" pp]
let retn formals freturn {caller_entry; state_from_call} (_, current) =
[%Trace.call fun {pf} -> pf "@,%a" State_domain.pp current]
;
(caller_entry, State_domain.retn formals freturn state_from_call current)
|>
[%Trace.retn fun {pf} -> pf "@,%a" pp]
let dnf (entry, current) =
List.map ~f:(fun c -> (entry, c)) (State_domain.dnf current)
let resolve_callee f e (entry, current) =
let callees, next = State_domain.resolve_callee f e current in
(callees, (entry, next))
type summary = State_domain.summary
let pp_summary = State_domain.pp_summary
let create_summary ~locals ~formals (entry, current) =
let fs, next =
State_domain.create_summary ~locals ~formals ~entry ~current
in
(fs, (entry, next))
let apply_summary (entry, current) summ =
let+ next = State_domain.apply_summary current summ in
(entry, next)
end