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