Summary: Generalize the lifting from State_domain (i.e. symbolic heaps) to Sh_domain (i.e. relations over symbolic heaps). Also, extract abstract-domain-related code into its own module/directory. Reviewed By: jberdine Differential Revision: D17319007 fbshipit-source-id: cefbd1393master
parent
2acb1c3dee
commit
3dc0c5938f
@ -0,0 +1,20 @@
|
||||
(* -*- tuareg -*- *)
|
||||
(*
|
||||
* 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.
|
||||
*)
|
||||
|
||||
let deps = ["import"; "llair_"]
|
||||
|
||||
;;
|
||||
Jbuild_plugin.V1.send
|
||||
@@ Format.sprintf {|
|
||||
(library
|
||||
(name domain)
|
||||
%s
|
||||
(libraries %s))
|
||||
|}
|
||||
(flags `lib deps)
|
||||
(libraries deps)
|
@ -0,0 +1,128 @@
|
||||
(*
|
||||
* 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_sig.Dom
|
||||
|
||||
val create_summary :
|
||||
locals:Var.Set.t
|
||||
-> formals:Var.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 sexp_of, equal]
|
||||
|
||||
let embed b = (b, b)
|
||||
|
||||
let pp fs (entry, curr) =
|
||||
Format.fprintf fs "@[<v 1> entry: %a@;current:%a@]" State_domain.pp
|
||||
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) =
|
||||
assert (State_domain.equal entry_b entry_a) ;
|
||||
(entry_a, State_domain.join current_a current_b)
|
||||
|
||||
let is_false (_, curr) = State_domain.is_false curr
|
||||
|
||||
let exec_assume (entry, current) cnd =
|
||||
match State_domain.exec_assume current cnd with
|
||||
| Some current -> Some (entry, current)
|
||||
| None -> None
|
||||
|
||||
let exec_kill (entry, current) reg =
|
||||
(entry, State_domain.exec_kill current reg)
|
||||
|
||||
let exec_move (entry, current) formal actual =
|
||||
(entry, State_domain.exec_move current formal actual)
|
||||
|
||||
let exec_inst (entry, current) inst =
|
||||
match State_domain.exec_inst current inst with
|
||||
| Ok current -> Ok (entry, current)
|
||||
| Error e -> Error e
|
||||
|
||||
let exec_intrinsic ~skip_throw (entry, current) areturn intrinsic actuals
|
||||
=
|
||||
match
|
||||
State_domain.exec_intrinsic ~skip_throw current areturn intrinsic
|
||||
actuals
|
||||
with
|
||||
| None -> None
|
||||
| Some (Ok current) -> Some (Ok (entry, current))
|
||||
| Some (Error e) -> Some (Error e)
|
||||
|
||||
type from_call =
|
||||
{state_from_call: State_domain.from_call; caller_entry: State_domain.t}
|
||||
[@@deriving sexp_of]
|
||||
|
||||
let call ~summaries actuals areturn formals locals globals_vec
|
||||
(entry, current) =
|
||||
let globals =
|
||||
Var.Set.of_vector
|
||||
(Vector.map globals_vec ~f:(fun (g : Global.t) -> g.var))
|
||||
in
|
||||
([%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 ",@ " Var.pp)
|
||||
(List.rev formals) Var.Set.pp locals Var.Set.pp globals
|
||||
State_domain.pp current]
|
||||
;
|
||||
let caller_current, state_from_call =
|
||||
State_domain.call ~summaries actuals areturn formals locals
|
||||
globals_vec 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" Var.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 (_, current) =
|
||||
State_domain.resolve_callee f e current
|
||||
|
||||
type summary = State_domain.summary
|
||||
|
||||
let pp_summary = State_domain.pp_summary
|
||||
|
||||
let create_summary ~locals ~formals (entry, current) =
|
||||
let fs, current =
|
||||
State_domain.create_summary ~locals ~formals ~entry ~current
|
||||
in
|
||||
(fs, (entry, current))
|
||||
|
||||
let apply_summary rel summ =
|
||||
let entry, current = rel in
|
||||
Option.map
|
||||
~f:(fun c -> (entry, c))
|
||||
(State_domain.apply_summary current summ)
|
||||
end
|
@ -0,0 +1,22 @@
|
||||
(*
|
||||
* 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 domain *)
|
||||
|
||||
module type State_domain_sig = sig
|
||||
include Domain_sig.Dom
|
||||
|
||||
val create_summary :
|
||||
locals:Var.Set.t
|
||||
-> formals:Var.Set.t
|
||||
-> entry:t
|
||||
-> current:t
|
||||
-> summary * t
|
||||
end
|
||||
|
||||
module Make (State_domain : State_domain_sig) : Domain_sig.Dom
|
@ -1,111 +0,0 @@
|
||||
(*
|
||||
* 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.
|
||||
*)
|
||||
|
||||
(** Abstract domain *)
|
||||
|
||||
type t = State_domain.t * State_domain.t
|
||||
|
||||
let embed q = (q, q)
|
||||
|
||||
let pp fs (entry, current) =
|
||||
Format.fprintf fs "@[<v 1> entry: %a@;current: %a@]" State_domain.pp entry
|
||||
State_domain.pp current
|
||||
|
||||
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) =
|
||||
assert (State_domain.equal entry_b entry_a) ;
|
||||
(entry_a, State_domain.join current_a current_b)
|
||||
|
||||
let is_false (_, curr) = State_domain.is_false curr
|
||||
|
||||
let exec_assume (entry, current) cnd =
|
||||
match State_domain.exec_assume current cnd with
|
||||
| Some current -> Some (entry, current)
|
||||
| None -> None
|
||||
|
||||
let exec_kill (entry, current) reg =
|
||||
(entry, State_domain.exec_kill current reg)
|
||||
|
||||
let exec_move (entry, current) formal actual =
|
||||
(entry, State_domain.exec_move current formal actual)
|
||||
|
||||
let exec_inst (entry, current) inst =
|
||||
match State_domain.exec_inst current inst with
|
||||
| Ok current -> Ok (entry, current)
|
||||
| Error e -> Error e
|
||||
|
||||
let exec_intrinsic ~skip_throw (entry, current) areturn intrinsic actuals =
|
||||
match
|
||||
State_domain.exec_intrinsic ~skip_throw current areturn intrinsic
|
||||
actuals
|
||||
with
|
||||
| None -> None
|
||||
| Some (Ok current) -> Some (Ok (entry, current))
|
||||
| Some (Error e) -> Some (Error e)
|
||||
|
||||
type from_call =
|
||||
{state_from_call: State_domain.from_call; caller_entry: State_domain.t}
|
||||
[@@deriving sexp_of]
|
||||
|
||||
let call ~summaries actuals areturn formals locals globals_vec
|
||||
(entry, current) =
|
||||
let globals =
|
||||
Var.Set.of_vector
|
||||
(Vector.map globals_vec ~f:(fun (g : Global.t) -> g.var))
|
||||
in
|
||||
([%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 ",@ " Var.pp)
|
||||
(List.rev formals) Var.Set.pp locals Var.Set.pp globals
|
||||
State_domain.pp current]
|
||||
;
|
||||
let caller_current, state_from_call =
|
||||
State_domain.call ~summaries actuals areturn formals locals globals
|
||||
current
|
||||
in
|
||||
((caller_current, caller_current), {state_from_call; caller_entry= entry}))
|
||||
|>
|
||||
[%Trace.retn fun {pf} (reln, _) -> pf "@,%a" pp reln]
|
||||
|
||||
let post locals {caller_entry} (_, current) =
|
||||
[%Trace.call fun {pf} -> pf "locals: %a" Var.Set.pp locals]
|
||||
;
|
||||
(caller_entry, State_domain.post locals 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 (_, current) =
|
||||
State_domain.resolve_callee f e current
|
||||
|
||||
type summary = State_domain.summary
|
||||
|
||||
let pp_summary = State_domain.pp_summary
|
||||
|
||||
let create_summary ~locals ~formals (entry, current) =
|
||||
let fs, current =
|
||||
State_domain.create_summary ~locals ~formals ~entry ~current
|
||||
in
|
||||
(fs, (entry, current))
|
||||
|
||||
let apply_summary (entry, current) fs =
|
||||
Option.map
|
||||
~f:(fun c -> (entry, c))
|
||||
(State_domain.apply_summary fs current)
|
@ -1,57 +0,0 @@
|
||||
(*
|
||||
* 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.
|
||||
*)
|
||||
|
||||
(** Abstract domain *)
|
||||
|
||||
type t
|
||||
|
||||
val pp : t pp
|
||||
val report_fmt_thunk : t -> Formatter.t -> unit
|
||||
val init : Global.t vector -> t
|
||||
val join : t -> t -> t
|
||||
val is_false : t -> bool
|
||||
val exec_assume : t -> Exp.t -> t option
|
||||
val exec_kill : t -> Var.t -> t
|
||||
val exec_move : t -> Var.t -> Exp.t -> t
|
||||
val exec_inst : t -> Llair.inst -> (t, unit) result
|
||||
|
||||
val exec_intrinsic :
|
||||
skip_throw:bool
|
||||
-> t
|
||||
-> Var.t option
|
||||
-> Var.t
|
||||
-> Exp.t list
|
||||
-> (t, unit) result option
|
||||
|
||||
type from_call [@@deriving sexp_of]
|
||||
type summary
|
||||
|
||||
val pp_summary : summary pp
|
||||
|
||||
(* formals should include all the parameters of the summary. That is both
|
||||
formals and globals.*)
|
||||
val create_summary :
|
||||
locals:Var.Set.t -> formals:Var.Set.t -> t -> summary * t
|
||||
|
||||
val apply_summary : t -> summary -> t option
|
||||
|
||||
val call :
|
||||
summaries:bool
|
||||
-> Exp.t list
|
||||
-> Var.t option
|
||||
-> Var.t list
|
||||
-> Var.Set.t
|
||||
-> Global.t vector
|
||||
-> t
|
||||
-> t * from_call
|
||||
|
||||
val post : Var.Set.t -> from_call -> t -> t
|
||||
val retn : Var.t list -> Var.t option -> from_call -> t -> t
|
||||
val dnf : t -> t list
|
||||
|
||||
val resolve_callee :
|
||||
(Var.t -> Llair.func list) -> Exp.t -> t -> Llair.func list
|
Loading…
Reference in new issue