[AI] Enable debugging only based on --write-html

Reviewed By: ezgicicek

Differential Revision: D10238681

fbshipit-source-id: 08eeedd26
master
Mehdi Bouaziz 6 years ago committed by Facebook Github Bot
parent 62b1f39540
commit 2be4710811

@ -9,6 +9,14 @@ open! IStd
module F = Format module F = Format
module L = Logging module L = Logging
type debug =
| Default
| DefaultNoExecInstr_UseFromLowerHilAbstractInterpreterOnly
(** If Default is used from LowerHil, debug html files will be opened twice and closed twice (boom!),
because both LowerHil-AI and SIL-AI want to print instructions and pre/post states.
When using LowerHil-AI, we're not interested in the underlying SIL instructions,
it's the only case where want to disable it. *)
type 'a state = {pre: 'a; post: 'a; visit_count: int} type 'a state = {pre: 'a; post: 'a; visit_count: int}
module type S = sig module type S = sig
@ -19,7 +27,7 @@ module type S = sig
type invariant_map = TransferFunctions.Domain.astate state InvariantMap.t type invariant_map = TransferFunctions.Domain.astate state InvariantMap.t
val compute_post : val compute_post :
?debug:bool ?debug:debug
-> TransferFunctions.extras ProcData.t -> TransferFunctions.extras ProcData.t
-> initial:TransferFunctions.Domain.astate -> initial:TransferFunctions.Domain.astate
-> TransferFunctions.Domain.astate option -> TransferFunctions.Domain.astate option
@ -28,7 +36,6 @@ module type S = sig
TransferFunctions.CFG.t TransferFunctions.CFG.t
-> TransferFunctions.extras ProcData.t -> TransferFunctions.extras ProcData.t
-> initial:TransferFunctions.Domain.astate -> initial:TransferFunctions.Domain.astate
-> debug:bool
-> invariant_map -> invariant_map
val exec_pdesc : val exec_pdesc :
@ -89,7 +96,8 @@ struct
let node_id = Node.id node in let node_id = Node.id node in
let update_inv_map pre ~visit_count = let update_inv_map pre ~visit_count =
let exec_instrs instrs = let exec_instrs instrs =
if debug then if Config.write_html && debug <> DefaultNoExecInstr_UseFromLowerHilAbstractInterpreterOnly
then
NodePrinter.start_session NodePrinter.start_session
~pp_name:(TransferFunctions.pp_session_name node) ~pp_name:(TransferFunctions.pp_session_name node)
(Node.underlying_node node) ; (Node.underlying_node node) ;
@ -101,7 +109,8 @@ struct
in in
Instrs.fold ~f:compute_post ~init:pre instrs Instrs.fold ~f:compute_post ~init:pre instrs
in in
if debug then ( if Config.write_html && debug <> DefaultNoExecInstr_UseFromLowerHilAbstractInterpreterOnly
then (
L.d_strln L.d_strln
( Format.asprintf "@[PRE: %a@]@\n@[INSTRS: %a@]@[POST: %a@]@." Domain.pp pre ( Format.asprintf "@[PRE: %a@]@\n@[INSTRS: %a@]@[POST: %a@]@." Domain.pp pre
(Instrs.pp Pp.text) instrs Domain.pp astate_post (Instrs.pp Pp.text) instrs Domain.pp astate_post
@ -123,7 +132,8 @@ struct
let prev = old_state.pre in let prev = old_state.pre in
let next = astate_pre in let next = astate_pre in
let res = Domain.widen ~prev ~next ~num_iters in let res = Domain.widen ~prev ~next ~num_iters in
if debug then debug_absint_operation (`Widen (num_iters, (prev, next, res))) node ; if Config.write_html then
debug_absint_operation (`Widen (num_iters, (prev, next, res))) node ;
res ) res )
else astate_pre else astate_pre
in in
@ -153,7 +163,8 @@ struct
some_post some_post
| Some joined_post -> | Some joined_post ->
let res = Domain.join joined_post post in let res = Domain.join joined_post post in
if debug then debug_absint_operation (`Join (joined_post, post, res)) node ; if Config.write_html then
debug_absint_operation (`Join (joined_post, post, res)) node ;
Some res ) ) Some res ) )
in in
match Scheduler.pop work_queue with match Scheduler.pop work_queue with
@ -173,7 +184,7 @@ struct
(* compute and return an invariant map for [cfg] *) (* compute and return an invariant map for [cfg] *)
let exec_cfg cfg proc_data ~initial ~debug = let exec_cfg_internal ~debug cfg proc_data ~initial =
let start_node = CFG.start_node cfg in let start_node = CFG.start_node cfg in
let inv_map', work_queue' = let inv_map', work_queue' =
exec_node start_node initial (Scheduler.empty cfg) InvariantMap.empty proc_data ~debug exec_node start_node initial (Scheduler.empty cfg) InvariantMap.empty proc_data ~debug
@ -181,15 +192,15 @@ struct
exec_worklist cfg work_queue' inv_map' proc_data ~debug exec_worklist cfg work_queue' inv_map' proc_data ~debug
(* compute and return an invariant map for [pdesc] *) let exec_cfg = exec_cfg_internal ~debug:Default
let exec_pdesc ({ProcData.pdesc} as proc_data) =
exec_cfg (CFG.from_pdesc pdesc) proc_data ~debug:Config.write_html
(* compute and return an invariant map for [pdesc] *)
let exec_pdesc ({ProcData.pdesc} as proc_data) = exec_cfg (CFG.from_pdesc pdesc) proc_data
(* compute and return the postcondition of [pdesc] *) (* compute and return the postcondition of [pdesc] *)
let compute_post ?(debug = Config.write_html) ({ProcData.pdesc} as proc_data) ~initial = let compute_post ?(debug = Default) ({ProcData.pdesc} as proc_data) ~initial =
let cfg = CFG.from_pdesc pdesc in let cfg = CFG.from_pdesc pdesc in
let inv_map = exec_cfg cfg proc_data ~initial ~debug in let inv_map = exec_cfg_internal cfg proc_data ~initial ~debug in
extract_post (Node.id (CFG.exit_node cfg)) inv_map extract_post (Node.id (CFG.exit_node cfg)) inv_map
end end

@ -7,6 +7,8 @@
open! IStd open! IStd
type debug = Default | DefaultNoExecInstr_UseFromLowerHilAbstractInterpreterOnly
type 'a state = {pre: 'a; post: 'a; visit_count: int} type 'a state = {pre: 'a; post: 'a; visit_count: int}
(** type of an intraprocedural abstract interpreter *) (** type of an intraprocedural abstract interpreter *)
@ -19,21 +21,18 @@ module type S = sig
type invariant_map = TransferFunctions.Domain.astate state InvariantMap.t type invariant_map = TransferFunctions.Domain.astate state InvariantMap.t
val compute_post : val compute_post :
?debug:bool ?debug:debug
-> TransferFunctions.extras ProcData.t -> TransferFunctions.extras ProcData.t
-> initial:TransferFunctions.Domain.astate -> initial:TransferFunctions.Domain.astate
-> TransferFunctions.Domain.astate option -> TransferFunctions.Domain.astate option
(** compute and return the postcondition for the given procedure starting from [initial]. If (** compute and return the postcondition for the given procedure starting from [initial]. *)
[debug] is true, print html debugging output. *)
val exec_cfg : val exec_cfg :
TransferFunctions.CFG.t TransferFunctions.CFG.t
-> TransferFunctions.extras ProcData.t -> TransferFunctions.extras ProcData.t
-> initial:TransferFunctions.Domain.astate -> initial:TransferFunctions.Domain.astate
-> debug:bool
-> invariant_map -> invariant_map
(** compute and return invariant map for the given CFG/procedure starting from [initial]. if (** compute and return invariant map for the given CFG/procedure starting from [initial]. *)
[debug] is true, print html debugging output. *)
val exec_pdesc : val exec_pdesc :
TransferFunctions.extras ProcData.t -> initial:TransferFunctions.Domain.astate -> invariant_map TransferFunctions.extras ProcData.t -> initial:TransferFunctions.Domain.astate -> invariant_map

@ -92,10 +92,12 @@ module MakeAbstractInterpreterWithConfig
struct struct
module Interpreter = AbstractInterpreter.Make (CFG) (Make (MakeTransferFunctions) (HilConfig)) module Interpreter = AbstractInterpreter.Make (CFG) (Make (MakeTransferFunctions) (HilConfig))
let debug = AbstractInterpreter.DefaultNoExecInstr_UseFromLowerHilAbstractInterpreterOnly
let compute_post ({ProcData.pdesc; tenv} as proc_data) ~initial = let compute_post ({ProcData.pdesc; tenv} as proc_data) ~initial =
Preanal.do_preanalysis pdesc tenv ; Preanal.do_preanalysis pdesc tenv ;
let initial' = (initial, IdAccessPathMapDomain.empty) in let initial' = (initial, IdAccessPathMapDomain.empty) in
Option.map ~f:fst (Interpreter.compute_post ~debug:false proc_data ~initial:initial') Option.map ~f:fst (Interpreter.compute_post ~debug proc_data ~initial:initial')
end end
module MakeAbstractInterpreter = MakeAbstractInterpreterWithConfig (DefaultConfig) module MakeAbstractInterpreter = MakeAbstractInterpreterWithConfig (DefaultConfig)

@ -124,9 +124,7 @@ let add_nullify_instrs pdesc tenv liveness_inv_map =
let nullify_proc_cfg = ProcCfg.Exceptional.from_pdesc pdesc in let nullify_proc_cfg = ProcCfg.Exceptional.from_pdesc pdesc in
let nullify_proc_data = ProcData.make pdesc tenv liveness_inv_map in let nullify_proc_data = ProcData.make pdesc tenv liveness_inv_map in
let initial = (VarDomain.empty, VarDomain.empty) in let initial = (VarDomain.empty, VarDomain.empty) in
let nullify_inv_map = let nullify_inv_map = NullifyAnalysis.exec_cfg nullify_proc_cfg nullify_proc_data ~initial in
NullifyAnalysis.exec_cfg nullify_proc_cfg nullify_proc_data ~initial ~debug:false
in
(* only nullify pvars that are local; don't nullify those that can escape *) (* only nullify pvars that are local; don't nullify those that can escape *)
let is_local pvar = not (Pvar.is_return pvar || Pvar.is_global pvar) in let is_local pvar = not (Pvar.is_return pvar || Pvar.is_global pvar) in
let node_nullify_instructions loc pvars = let node_nullify_instructions loc pvars =
@ -172,9 +170,7 @@ let do_liveness pdesc tenv =
let liveness_proc_cfg = BackwardCfg.from_pdesc pdesc in let liveness_proc_cfg = BackwardCfg.from_pdesc pdesc in
let initial = Liveness.Domain.empty in let initial = Liveness.Domain.empty in
let liveness_inv_map = let liveness_inv_map =
LivenessAnalysis.exec_cfg liveness_proc_cfg LivenessAnalysis.exec_cfg liveness_proc_cfg (ProcData.make_default pdesc tenv) ~initial
(ProcData.make_default pdesc tenv)
~initial ~debug:false
in in
add_nullify_instrs pdesc tenv liveness_inv_map ; add_nullify_instrs pdesc tenv liveness_inv_map ;
Procdesc.signal_did_preanalysis pdesc Procdesc.signal_did_preanalysis pdesc

@ -746,7 +746,6 @@ let checker ({Callbacks.tenv; proc_desc} as callback_args) : Summary.t =
let reaching_defs_invariant_map = let reaching_defs_invariant_map =
ReachingDefs.Analyzer.exec_cfg node_cfg proc_data ReachingDefs.Analyzer.exec_cfg node_cfg proc_data
~initial:(ReachingDefs.init_reaching_defs_with_formals proc_desc) ~initial:(ReachingDefs.init_reaching_defs_with_formals proc_desc)
~debug:false
in in
(* collect all prune nodes that occur in loop guards, needed for ControlDepAnalyzer *) (* collect all prune nodes that occur in loop guards, needed for ControlDepAnalyzer *)
let control_maps, loop_head_to_loop_nodes = Loop_control.get_control_maps node_cfg in let control_maps, loop_head_to_loop_nodes = Loop_control.get_control_maps node_cfg in
@ -754,14 +753,12 @@ let checker ({Callbacks.tenv; proc_desc} as callback_args) : Summary.t =
let control_dep_invariant_map = let control_dep_invariant_map =
let proc_data = ProcData.make proc_desc tenv control_maps in let proc_data = ProcData.make proc_desc tenv control_maps in
Control.ControlDepAnalyzer.exec_cfg node_cfg proc_data ~initial:Control.ControlDepSet.empty Control.ControlDepAnalyzer.exec_cfg node_cfg proc_data ~initial:Control.ControlDepSet.empty
~debug:false
in in
let instr_cfg = InstrCFG.from_pdesc proc_desc in let instr_cfg = InstrCFG.from_pdesc proc_desc in
let invariant_map_NodesBasicCost = let invariant_map_NodesBasicCost =
let proc_data = ProcData.make proc_desc tenv inferbo_invariant_map in let proc_data = ProcData.make proc_desc tenv inferbo_invariant_map in
(*compute_WCET cfg invariant_map min_trees in *) (*compute_WCET cfg invariant_map min_trees in *)
AnalyzerNodesBasicCost.exec_cfg instr_cfg proc_data ~initial:NodesBasicCostDomain.empty AnalyzerNodesBasicCost.exec_cfg instr_cfg proc_data ~initial:NodesBasicCostDomain.empty
~debug:false
in in
(* compute loop invariant map for control var analysis *) (* compute loop invariant map for control var analysis *)
let loop_inv_map = let loop_inv_map =
@ -779,10 +776,9 @@ let checker ({Callbacks.tenv; proc_desc} as callback_args) : Summary.t =
in in
let initWCET = (BasicCost.zero, ReportedOnNodes.empty) in let initWCET = (BasicCost.zero, ReportedOnNodes.empty) in
match match
AnalyzerWCET.compute_post AnalyzerWCET.compute_post ~initial:initWCET
(ProcData.make proc_desc tenv (ProcData.make proc_desc tenv
{basic_cost_map= invariant_map_NodesBasicCost; get_node_nb_exec; summary}) {basic_cost_map= invariant_map_NodesBasicCost; get_node_nb_exec; summary})
~debug:false ~initial:initWCET
with with
| Some (exit_cost, _) -> | Some (exit_cost, _) ->
L.internal_error "@\n[COST ANALYSIS] PROCEDURE '%a' |CFG| = %i FINAL COST = %a @\n" L.internal_error "@\n[COST ANALYSIS] PROCEDURE '%a' |CFG| = %i FINAL COST = %a @\n"

@ -80,7 +80,6 @@ let checker {Callbacks.tenv; summary; proc_desc} : Summary.t =
let reaching_defs_invariant_map = let reaching_defs_invariant_map =
ReachingDefs.Analyzer.exec_cfg cfg proc_data ReachingDefs.Analyzer.exec_cfg cfg proc_data
~initial:(ReachingDefs.init_reaching_defs_with_formals proc_desc) ~initial:(ReachingDefs.init_reaching_defs_with_formals proc_desc)
~debug:false
in in
(* get dominators *) (* get dominators *)
let idom = Dominators.get_idoms proc_desc in let idom = Dominators.get_idoms proc_desc in

@ -122,14 +122,14 @@ module CapturedByRefAnalyzer =
let get_captured_by_ref_invariant_map proc_desc proc_data = let get_captured_by_ref_invariant_map proc_desc proc_data =
let cfg = ProcCfg.Exceptional.from_pdesc proc_desc in let cfg = ProcCfg.Exceptional.from_pdesc proc_desc in
CapturedByRefAnalyzer.exec_cfg cfg proc_data ~initial:VarSet.empty ~debug:false CapturedByRefAnalyzer.exec_cfg cfg proc_data ~initial:VarSet.empty
let checker {Callbacks.tenv; summary; proc_desc} : Summary.t = let checker {Callbacks.tenv; summary; proc_desc} : Summary.t =
let proc_data = ProcData.make_default proc_desc tenv in let proc_data = ProcData.make_default proc_desc tenv in
let captured_by_ref_invariant_map = get_captured_by_ref_invariant_map proc_desc proc_data in let captured_by_ref_invariant_map = get_captured_by_ref_invariant_map proc_desc proc_data in
let cfg = CFG.from_pdesc proc_desc in let cfg = CFG.from_pdesc proc_desc in
let invariant_map = Analyzer.exec_cfg cfg proc_data ~initial:Domain.empty ~debug:false in let invariant_map = Analyzer.exec_cfg cfg proc_data ~initial:Domain.empty in
(* we don't want to report in harmless cases like int i = 0; if (...) { i = ... } else { i = ... } (* we don't want to report in harmless cases like int i = 0; if (...) { i = ... } else { i = ... }
that create an intentional dead store as an attempt to imitate default value semantics. that create an intentional dead store as an attempt to imitate default value semantics.
use dead stores to a "sentinel" value as a heuristic for ignoring this case *) use dead stores to a "sentinel" value as a heuristic for ignoring this case *)

Loading…
Cancel
Save