Skip to content
Snippets Groups Projects
Commit 10750609 authored by David Bühler's avatar David Bühler
Browse files

Merge branch 'feature/eva/ivette-values' into 'master'

[Eva] Improves values request: allows evaluations of function parameters, predicates and term lvals

Closes #1238

See merge request frama-c/frama-c!4134
parents ef52e05a 051ef5ad
No related branches found
No related tags found
No related merge requests found
...@@ -122,8 +122,8 @@ export const getStmtInfo: Server.GetRequest< ...@@ -122,8 +122,8 @@ export const getStmtInfo: Server.GetRequest<
const getProbeInfo_internal: Server.GetRequest< const getProbeInfo_internal: Server.GetRequest<
marker, marker,
{ condition: boolean, effects: boolean, rank: number, stmt?: marker, { condition: boolean, effects: boolean, stmt?: marker, code?: string,
code?: string, evaluable: boolean } evaluable: boolean }
> = { > = {
kind: Server.RqKind.GET, kind: Server.RqKind.GET,
name: 'plugins.eva.values.getProbeInfo', name: 'plugins.eva.values.getProbeInfo',
...@@ -131,7 +131,6 @@ const getProbeInfo_internal: Server.GetRequest< ...@@ -131,7 +131,6 @@ const getProbeInfo_internal: Server.GetRequest<
output: Json.jObject({ output: Json.jObject({
condition: Json.jBoolean, condition: Json.jBoolean,
effects: Json.jBoolean, effects: Json.jBoolean,
rank: Json.jNumber,
stmt: Json.jOption(jMarker), stmt: Json.jOption(jMarker),
code: Json.jOption(Json.jString), code: Json.jOption(Json.jString),
evaluable: Json.jBoolean, evaluable: Json.jBoolean,
...@@ -141,8 +140,8 @@ const getProbeInfo_internal: Server.GetRequest< ...@@ -141,8 +140,8 @@ const getProbeInfo_internal: Server.GetRequest<
/** Probe informations */ /** Probe informations */
export const getProbeInfo: Server.GetRequest< export const getProbeInfo: Server.GetRequest<
marker, marker,
{ condition: boolean, effects: boolean, rank: number, stmt?: marker, { condition: boolean, effects: boolean, stmt?: marker, code?: string,
code?: string, evaluable: boolean } evaluable: boolean }
>= getProbeInfo_internal; >= getProbeInfo_internal;
/** Evaluation of an expression or lvalue */ /** Evaluation of an expression or lvalue */
......
...@@ -211,19 +211,22 @@ function useProbeCache(): Request<Location, Probe> { ...@@ -211,19 +211,22 @@ function useProbeCache(): Request<Location, Probe> {
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
interface StmtProps { interface StmtProps {
fct?: string;
stmt?: Ast.marker; stmt?: Ast.marker;
marker?: Ast.marker; marker?: Ast.marker;
short?: boolean; short?: boolean;
} }
function Stmt(props: StmtProps): JSX.Element | null { function Stmt(props: StmtProps): JSX.Element | null {
const { stmt, marker, short } = props; const { fct, stmt, marker, short } = props;
const { descr, sloc } = States.useMarker(marker); const { descr } = States.useMarker(stmt);
if (!stmt || !marker) return null; const { sloc } = States.useMarker(marker);
if (!marker || !fct) return null;
// Location sloc should always be defined for statements. // Location sloc should always be defined for statements.
const label = short ? `@L${sloc?.line}` : `@${sloc?.base}:${sloc?.line}`; const label = short ? `@L${sloc?.line}` : `@${sloc?.base}:${sloc?.line}`;
const title = stmt ? descr : "Start of function " + fct;
const className = 'dome-text-cell eva-stmt'; const className = 'dome-text-cell eva-stmt';
return <span className={className} title={descr}>{label}</span>; return <span className={className} title={title}>{label}</span>;
} }
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
...@@ -290,7 +293,7 @@ async function StackInfos(props: StackInfosProps): Promise<JSX.Element> { ...@@ -290,7 +293,7 @@ async function StackInfos(props: StackInfosProps): Promise<JSX.Element> {
onDoubleClick={onDoubleClick} onDoubleClick={onDoubleClick}
> >
{caller} {caller}
<Stmt stmt={stmt} marker={stmt} /> <Stmt fct={caller} stmt={stmt} marker={stmt} />
</Cell> </Cell>
); );
}; };
...@@ -386,7 +389,7 @@ function ProbeHeader(props: ProbeHeaderProps): JSX.Element { ...@@ -386,7 +389,7 @@ function ProbeHeader(props: ProbeHeaderProps): JSX.Element {
<div className='eva-header-text-overflow'> <div className='eva-header-text-overflow'>
<span className='dome-text-cell' title={code}>{code}</span> <span className='dome-text-cell' title={code}>{code}</span>
</div> </div>
<Stmt stmt={stmt} marker={target} short={true}/> <Stmt fct={fct} stmt={stmt} marker={target} short={true}/>
</TableCell> </TableCell>
</th> </th>
); );
...@@ -412,17 +415,22 @@ function ProbeDescr(props: ProbeDescrProps): JSX.Element[] { ...@@ -412,17 +415,22 @@ function ProbeDescr(props: ProbeDescrProps): JSX.Element[] {
const valuesClass = classes('eva-table-values', 'eva-table-values-center'); const valuesClass = classes('eva-table-values', 'eva-table-values-center');
const tableClass = classes('eva-table-descrs', 'eva-table-descr-sticky'); const tableClass = classes('eva-table-descrs', 'eva-table-descr-sticky');
const cls = classes(valuesClass, tableClass); const cls = classes(valuesClass, tableClass);
const title = (s: string): string => `Values ${s} the statement evaluation`;
const elements: JSX.Element[] = []; const elements: JSX.Element[] = [];
function push(title: string, children: JSX.Element | string): void { function push(title: string, children: JSX.Element | string): void {
elements.push(<td className={cls} title={title}>{children}</td>); elements.push(<td className={cls} title={title}>{children}</td>);
} }
if (!probe.effects && !probe.condition) if (!probe.effects && !probe.condition) {
push('Values at the statement', '-'); if (probe.stmt)
push('Values at the statement', '-');
else if (probe.fct)
push('Values at the start of function ' + probe.fct, '-');
else
push('Values at the start of the analysis', '-');
}
if (probe.effects || probe.condition) if (probe.effects || probe.condition)
push(title('before'), 'Before'); push('Values just before the statement', 'Before');
if (probe.effects) if (probe.effects)
push(title('after'), 'After'); push('Values just after the statement', 'After');
if (probe.condition) { if (probe.condition) {
const pushCondition = (s: string): void => { const pushCondition = (s: string): void => {
const t = `Values after the condition, in the ${s.toLowerCase()} branch`; const t = `Values after the condition, in the ${s.toLowerCase()} branch`;
......
...@@ -183,31 +183,81 @@ let () = Request.register ~package ...@@ -183,31 +183,81 @@ let () = Request.register ~package
(* ----- Register Eva values information ------------------------------------ *) (* ----- Register Eva values information ------------------------------------ *)
let term_lval_to_lval tlval = type evaluation_point =
try Logic_to_c.term_lval_to_lval tlval | Initial
| Pre of kernel_function
| Stmt of kernel_function * stmt
let post kf =
if Analysis.use_spec_instead_of_definition kf
then raise Not_found
else
try Stmt (kf, Kernel_function.find_return kf)
with Kernel_function.No_Statement -> raise Not_found
let request_at = function
| Initial -> Results.at_start
| Stmt (_, stmt) -> Results.before stmt
| Pre kf -> Results.at_start_of kf
let property_evaluation_point = function
| Property.IPCodeAnnot { ica_kf = kf; ica_stmt = stmt }
| IPPropertyInstance { ii_kf = kf; ii_stmt = stmt } -> Stmt (kf, stmt)
| IPPredicate {ip_kf; ip_kind = PKEnsures (_, Normal)} -> post ip_kf
| IPPredicate { ip_kf = kf;
ip_kind = PKRequires _ | PKAssumes _ | PKTerminates }
| IPAssigns {ias_kf = kf} | IPFrom {if_kf = kf} ->
Pre kf
| IPPredicate _ | IPComplete _ | IPDisjoint _ | IPDecrease _
| IPAxiomatic _ | IPLemma _ | IPTypeInvariant _ | IPGlobalInvariant _
| IPOther _ | IPAllocation _ | IPReachable _ | IPExtended _ | IPBehavior _ ->
raise Not_found
let marker_evaluation_point = function
| Printer_tag.PGlobal _ -> Initial
| PStmt (kf, stmt) | PStmtStart (kf, stmt) -> Stmt (kf, stmt)
| PLval (kf, ki, _) | PExp (kf, ki, _) | PVDecl (kf, ki, _) ->
begin
match kf, ki with
| Some kf, Kstmt stmt -> Stmt (kf, stmt)
| Some kf, Kglobal -> Pre kf
| None, Kglobal -> Initial
| None, Kstmt _ -> assert false
end
| PTermLval (_, _, prop, _) | PIP prop -> property_evaluation_point prop
| PType _ -> raise Not_found
let term_lval_to_lval kf tlval =
try
let result = Option.bind kf Eva_utils.find_return_var in
Logic_to_c.term_lval_to_lval ?result tlval
with Logic_to_c.No_conversion -> raise Not_found with Logic_to_c.No_conversion -> raise Not_found
let print_value fmt loc = let print_value fmt loc =
let is_scalar = Cil.isScalarType in let is_scalar = Cil.isScalarType in
let kinstr, eval = let evaluation_point = marker_evaluation_point loc in
let request = request_at evaluation_point in
let eval =
match loc with match loc with
| Printer_tag.PLval (_kf, ki, lval) when is_scalar (Cil.typeOfLval lval) -> | Printer_tag.PLval (_, _, lval) when is_scalar (Cil.typeOfLval lval) ->
ki, Results.eval_lval lval Results.eval_lval lval
| Printer_tag.PExp (_kf, ki, expr) when is_scalar (Cil.typeOf expr) -> | Printer_tag.PExp (_, _, expr) when is_scalar (Cil.typeOf expr) ->
ki, Results.eval_exp expr Results.eval_exp expr
| PVDecl (_kf, ki, vi) when is_scalar vi.vtype -> | PVDecl (_, _, vi) when is_scalar vi.vtype ->
ki, Results.eval_var vi Results.eval_var vi
| PTermLval (_kf, ki, _ip, tlval) -> | PTermLval (kf, _, _ip, tlval) ->
let lval = term_lval_to_lval tlval in let lval = term_lval_to_lval kf tlval in
ki, Results.eval_lval lval if is_scalar (Cil.typeOfLval lval)
then Results.eval_lval lval
else raise Not_found
| _ -> raise Not_found | _ -> raise Not_found
in in
let pretty = Cvalue.V_Or_Uninitialized.pretty in let pretty = Cvalue.V_Or_Uninitialized.pretty in
let eval_cvalue at = Results.(eval at |> as_cvalue_or_uninitialized) in let eval_cvalue at = Results.(eval at |> as_cvalue_or_uninitialized) in
let before = eval_cvalue (Results.before_kinstr kinstr) in let before = eval_cvalue request in
match kinstr with match evaluation_point with
| Kglobal -> pretty fmt before | Initial | Pre _ -> pretty fmt before
| Kstmt stmt -> | Stmt (_, stmt) ->
let after = eval_cvalue (Results.after stmt) in let after = eval_cvalue (Results.after stmt) in
if Cvalue.V_Or_Uninitialized.equal before after if Cvalue.V_Or_Uninitialized.equal before after
then pretty fmt before then pretty fmt before
...@@ -241,8 +291,8 @@ module EvaTaints = struct ...@@ -241,8 +291,8 @@ module EvaTaints = struct
| PLval (_, Kstmt stmt, lval) -> Some (expr_of_lval lval, stmt) | PLval (_, Kstmt stmt, lval) -> Some (expr_of_lval lval, stmt)
| PExp (_, Kstmt stmt, expr) -> Some (expr, stmt) | PExp (_, Kstmt stmt, expr) -> Some (expr, stmt)
| PVDecl (_, Kstmt stmt, vi) -> Some (expr_of_lval (Var vi, NoOffset), stmt) | PVDecl (_, Kstmt stmt, vi) -> Some (expr_of_lval (Var vi, NoOffset), stmt)
| PTermLval (_, Kstmt stmt, _, tlval) -> | PTermLval (kf, Kstmt stmt, _, tlval) ->
Some (term_lval_to_lval tlval |> expr_of_lval, stmt) Some (term_lval_to_lval kf tlval |> expr_of_lval, stmt)
| _ -> None | _ -> None
let of_marker marker = let of_marker marker =
......
...@@ -21,3 +21,18 @@ ...@@ -21,3 +21,18 @@
(**************************************************************************) (**************************************************************************)
(** General Eva requests registered in the server. *) (** General Eva requests registered in the server. *)
open Cil_types
type evaluation_point =
| Initial
| Pre of kernel_function
| Stmt of kernel_function * stmt
(* Returns the evaluation point of a marker.
@raise Not_found if the marker cannot be evaluated. *)
val marker_evaluation_point: Printer_tag.localizable -> evaluation_point
(* Converts an ACSL lval into a C lval.
@raise Not_found if the conversion fails. *)
val term_lval_to_lval: kernel_function option -> term_lval -> lval
...@@ -42,9 +42,12 @@ let package = ...@@ -42,9 +42,12 @@ let package =
~title:"Eva Values" ~title:"Eva Values"
() ()
type probe = type term = Pexpr of exp | Plval of lval | Ppred of predicate
| Pexpr of exp * stmt type evaluation_point = General_requests.evaluation_point =
| Plval of lval * stmt Initial | Pre of kernel_function | Stmt of kernel_function * stmt
(* A term and the program point where it should be evaluated. *)
type probe = term * evaluation_point
type callstack = Value_types.callstack type callstack = Value_types.callstack
type truth = Abstract_interp.truth type truth = Abstract_interp.truth
...@@ -81,32 +84,52 @@ let () = Analysis.register_computation_hook ~on:Computed ...@@ -81,32 +84,52 @@ let () = Analysis.register_computation_hook ~on:Computed
(* --- Marker Utilities --- *) (* --- Marker Utilities --- *)
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
let next_steps s = let next_steps = function
match s.skind with | Initial | Pre _ -> []
| If (cond, _, _, _) -> [ `Then cond ; `Else cond ] | Stmt (_, stmt) ->
| Instr (Set _ | Call _ | Local_init _) -> [ `After ] match stmt.skind with
| Instr (Asm _ | Code_annot _) | If (cond, _, _, _) -> [ `Then cond ; `Else cond ]
| Switch _ | Loop _ | Block _ | UnspecifiedSequence _ | Instr (Set _ | Call _ | Local_init _) -> [ `After ]
| TryCatch _ | TryFinally _ | TryExcept _ | Instr (Asm _ | Code_annot _)
| Instr (Skip _) | Return _ | Break _ | Continue _ | Goto _ | Throw _ -> [] | Switch _ | Loop _ | Block _ | UnspecifiedSequence _
| TryCatch _ | TryFinally _ | TryExcept _
let probe_stmt s = | Instr (Skip _) | Return _ | Break _ | Continue _ | Goto _ | Throw _ -> []
match s.skind with
| Instr (Set(lv,_,_)) -> Some (Plval (lv,s)) let probe_stmt stmt =
| Instr (Call(Some lr,_,_,_)) -> Some (Plval (lr,s)) match stmt.skind with
| Instr (Local_init(v,_,_)) -> Some (Plval ((Var v,NoOffset), s)) | Instr (Set (lv, _, _))
| Return (Some e,_) | If(e,_,_,_) | Switch(e,_,_,_) -> Some (Pexpr (e,s)) | Instr (Call (Some lv, _, _, _)) -> Plval lv
| _ -> None | Instr (Local_init (v, _, _)) -> Plval (Var v, NoOffset)
| Return (Some e, _) | If (e, _, _, _) | Switch (e, _, _, _) -> Pexpr e
| _ -> raise Not_found
let probe_code_annot = function
| AAssert (_, p) | AInvariant (_, true, p) -> Ppred p.tp_statement
| _ -> raise Not_found
let probe_property = function
| Property.IPCodeAnnot ica -> probe_code_annot ica.ica_ca.annot_content
| IPPropertyInstance { ii_pred = Some pred }
| IPPredicate {ip_pred = pred} ->
Ppred (Logic_const.pred_of_id_pred pred)
| _ -> raise Not_found
let probe_marker = function
| Printer_tag.PLval (_, _, (Var vi, NoOffset))
| PVDecl (_, _, vi) when Cil.isFunctionType vi.vtype -> raise Not_found
| PLval (_, _, l) -> Plval l
| PExp (_, _, e) -> Pexpr e
| PStmt (_, s) | PStmtStart (_, s) -> probe_stmt s
| PVDecl (_, _, v) -> Plval (Var v, NoOffset)
| PTermLval (kf, _, _, tlval) ->
Plval (General_requests.term_lval_to_lval kf tlval)
| PIP property -> probe_property property
| _ -> raise Not_found
let probe marker = let probe marker =
let open Printer_tag in try Some (probe_marker marker,
match marker with General_requests.marker_evaluation_point marker)
| PLval (_, _, (Var vi, NoOffset)) when Cil.isFunctionType vi.vtype -> None with Not_found -> None
| PLval(_,Kstmt s,l) -> Some (Plval (l,s))
| PExp(_,Kstmt s,e) -> Some (Pexpr (e,s))
| PStmt(_,s) | PStmtStart(_,s) -> probe_stmt s
| PVDecl(_,Kstmt s,v) -> Some (Plval ((Var v,NoOffset),s))
| _ -> None
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
(* --- Stmt Ranking --- *) (* --- Stmt Ranking --- *)
...@@ -329,7 +352,8 @@ let filter_variables bases = ...@@ -329,7 +352,8 @@ let filter_variables bases =
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
module type EvaProxy = sig module type EvaProxy = sig
val callstacks : stmt -> callstack list val kf_callstacks : kernel_function -> callstack list
val stmt_callstacks : stmt -> callstack list
val evaluate : probe -> callstack option -> evaluations val evaluate : probe -> callstack option -> evaluations
end end
...@@ -346,20 +370,34 @@ module Proxy(A : Analysis.S) : EvaProxy = struct ...@@ -346,20 +370,34 @@ module Proxy(A : Analysis.S) : EvaProxy = struct
let default = fun _ -> Cvalue.V.top in let default = fun _ -> Cvalue.V.top in
Option.value ~default (A.Val.get Main_values.CVal.key) Option.value ~default (A.Val.get Main_values.CVal.key)
let callstacks stmt = let callstacks get_state_by_callstack elt =
match A.get_stmt_state_by_callstack ~after:false stmt with match get_state_by_callstack elt with
| `Top | `Bottom -> [] | `Top | `Bottom -> []
| `Value states -> CSmap.fold_sorted (fun cs _ wcs -> cs :: wcs) states [] | `Value states -> CSmap.fold (fun cs _ acc -> cs :: acc) states []
let kf_callstacks = callstacks A.get_initial_state_by_callstack
let stmt_callstacks = callstacks (A.get_stmt_state_by_callstack ~after:false)
let dstate ~after stmt = function let get_state get_consolidated get_by_callstack arg = function
| None -> (A.get_stmt_state ~after stmt :> dstate) | None -> get_consolidated arg
| Some cs -> | Some cs ->
match A.get_stmt_state_by_callstack ~selection:[cs] ~after stmt with match get_by_callstack ?selection:(Some [cs]) arg with
| (`Top | `Bottom) as res -> res | (`Top | `Bottom) as res -> res
| `Value cmap -> | `Value cmap ->
try `Value (CSmap.find cmap cs) try `Value (CSmap.find cmap cs)
with Not_found -> `Bottom with Not_found -> `Bottom
let get_stmt_state ~after =
get_state (A.get_stmt_state ~after) (A.get_stmt_state_by_callstack ~after)
let get_initial_state =
get_state A.get_initial_state A.get_initial_state_by_callstack
let domain_state callstack = function
| Initial -> A.get_global_state ()
| Pre kf -> get_initial_state kf callstack
| Stmt (_, stmt) -> get_stmt_state ~after:false stmt callstack
(* --- Converts an evaluation [result] into an exported [value]. ---------- *) (* --- Converts an evaluation [result] into an exported [value]. ---------- *)
(* Result of an evaluation: a generic value for scalar types, or an offsetmap (* Result of an evaluation: a generic value for scalar types, or an offsetmap
...@@ -367,37 +405,42 @@ module Proxy(A : Analysis.S) : EvaProxy = struct ...@@ -367,37 +405,42 @@ module Proxy(A : Analysis.S) : EvaProxy = struct
type result = type result =
| Value of A.Val.t | Value of A.Val.t
| Offsetmap of offsetmap | Offsetmap of offsetmap
| Status of truth
let pp_result typ fmt = function let pp_result typ fmt = function
| Value v -> A.Val.pretty fmt v | Value v -> A.Val.pretty fmt v
| Offsetmap offsm -> pp_offsetmap typ fmt offsm | Offsetmap offsm -> pp_offsetmap typ fmt offsm
| Status truth -> Alarmset.Status.pretty fmt truth
let get_pointed_bases = function let get_pointed_bases = function
| Value v -> get_bases (get_cvalue v) | Value v -> get_bases (get_cvalue v)
| Offsetmap offsm -> get_pointed_bases offsm | Offsetmap offsm -> get_pointed_bases offsm
| Status _ -> Base.Hptset.empty
let get_pointed_markers stmt result = let get_pointed_markers eval_point result =
let bases = get_pointed_bases result in let bases = get_pointed_bases result in
let vars = filter_variables bases in let vars = filter_variables bases in
let kf = let kf, kinstr =
try Some (Kernel_function.find_englobing_kf stmt) match eval_point with
with Not_found -> None | Initial -> None, Kglobal
| Pre kf -> Some kf, Kglobal
| Stmt (kf, stmt) -> Some kf, Kstmt stmt
in in
let to_marker vi = let to_marker vi =
let text = Pretty_utils.to_string Printer.pp_varinfo vi in let text = Pretty_utils.to_string Printer.pp_varinfo vi in
let marker = Printer_tag.PLval (kf, Kstmt stmt, Cil.var vi) in let marker = Printer_tag.PLval (kf, kinstr, Cil.var vi) in
text, marker text, marker
in in
List.map to_marker vars List.map to_marker vars
(* Creates an exported [value] from an evaluation result. *) (* Creates an exported [value] from an evaluation result. *)
let make_value typ stmt (result, alarms) = let make_value typ eval_point (result, alarms) =
let descr = Format.asprintf "@[<hov 2>%a@]" Alarms.pretty in let descr = Format.asprintf "@[<hov 2>%a@]" Alarms.pretty in
let f alarm status acc = (status, descr alarm) :: acc in let f alarm status acc = (status, descr alarm) :: acc in
let alarms = Alarmset.fold f [] alarms |> List.rev in let alarms = Alarmset.fold f [] alarms |> List.rev in
let pretty_eval = Bottom.pretty (pp_result typ) in let pretty_eval = Bottom.pretty (pp_result typ) in
let value = Pretty_utils.to_string pretty_eval result in let value = Pretty_utils.to_string pretty_eval result in
let pointed_markers = get_pointed_markers stmt in let pointed_markers = get_pointed_markers eval_point in
let pointed_vars = Bottom.fold ~bottom:[] pointed_markers result in let pointed_vars = Bottom.fold ~bottom:[] pointed_markers result in
{ value; alarms; pointed_vars } { value; alarms; pointed_vars }
...@@ -425,6 +468,18 @@ module Proxy(A : Analysis.S) : EvaProxy = struct ...@@ -425,6 +468,18 @@ module Proxy(A : Analysis.S) : EvaProxy = struct
let eval_expr expr state = let eval_expr expr state =
A.eval_expr state expr >>=: fun value -> Value value A.eval_expr state expr >>=: fun value -> Value value
let eval_pred eval_point predicate state =
let result =
match eval_point with
| Initial | Pre _ -> None
| Stmt (kf, _) -> Eva_utils.find_return_var kf
in
let env =
Abstract_domain.{ states = (function _ -> A.Dom.top) ; result }
in
let truth = A.Dom.evaluate_predicate env state predicate in
`Value (Status truth), Alarmset.none
(* --- Evaluates all steps (before/after the statement). ------------------ *) (* --- Evaluates all steps (before/after the statement). ------------------ *)
let do_next eval state stmt callstack = let do_next eval state stmt callstack =
...@@ -434,32 +489,34 @@ module Proxy(A : Analysis.S) : EvaProxy = struct ...@@ -434,32 +489,34 @@ module Proxy(A : Analysis.S) : EvaProxy = struct
let else_state = (A.assume_cond stmt state cond false :> dstate) in let else_state = (A.assume_cond stmt state cond false :> dstate) in
Cond (eval then_state, eval else_state) Cond (eval then_state, eval else_state)
| Instr (Set _ | Call _ | Local_init _) -> | Instr (Set _ | Call _ | Local_init _) ->
let after_state = dstate ~after:true stmt callstack in let after_state = get_stmt_state ~after:true stmt callstack in
After (eval after_state) After (eval after_state)
| _ -> Nothing | _ -> Nothing
let eval_steps typ eval stmt callstack = let eval_steps typ eval eval_point callstack =
let default value = { value; alarms = []; pointed_vars = []; } in let default value = { value; alarms = []; pointed_vars = []; } in
let eval = function let eval = function
| `Bottom -> default "Unreachable" | `Bottom -> default "Unreachable"
| `Top -> default "No information" | `Top -> default "No information"
| `Value state -> make_value typ stmt (eval state) | `Value state -> make_value typ eval_point (eval state)
in in
let before = dstate ~after:false stmt callstack in let before = domain_state callstack eval_point in
let here = eval before in let here = eval before in
let next = let next =
match before with match before, eval_point with
| `Bottom | `Top -> Nothing | `Value state, Stmt (_, stmt) -> do_next eval state stmt callstack
| `Value state -> do_next eval state stmt callstack | _ -> Nothing
in in
{ here; next; } { here; next; }
let evaluate p callstack = let evaluate (term, eval_point) callstack =
match p with match term with
| Plval (lval, stmt) -> | Plval lval ->
eval_steps (Cil.typeOfLval lval) (eval_lval lval) stmt callstack eval_steps (Cil.typeOfLval lval) (eval_lval lval) eval_point callstack
| Pexpr (expr, stmt) -> | Pexpr expr ->
eval_steps (Cil.typeOf expr) (eval_expr expr) stmt callstack eval_steps (Cil.typeOf expr) (eval_expr expr) eval_point callstack
| Ppred pred ->
eval_steps Cil.intType (eval_pred eval_point pred) eval_point callstack
end end
let proxy = let proxy =
...@@ -481,11 +538,14 @@ let () = ...@@ -481,11 +538,14 @@ let () =
~output:(module Jlist(Jcallstack)) ~output:(module Jlist(Jcallstack))
begin fun markers -> begin fun markers ->
let module A : EvaProxy = (val proxy ()) in let module A : EvaProxy = (val proxy ()) in
let add stmt = List.fold_right CSet.add (A.callstacks stmt) in
let gather_callstacks cset marker = let gather_callstacks cset marker =
match probe marker with let list =
| Some (Pexpr (_, stmt) | Plval (_, stmt)) -> add stmt cset match probe marker with
| None -> cset | Some (_, Stmt (_, stmt)) -> A.stmt_callstacks stmt
| Some (_, Pre kf) -> A.kf_callstacks kf
| Some (_, Initial) | None -> []
in
List.fold_left (fun set elt -> CSet.add elt set) cset list
in in
let cset = List.fold_left gather_callstacks CSet.empty markers in let cset = List.fold_left gather_callstacks CSet.empty markers in
Ranking.sort (CSet.elements cset) Ranking.sort (CSet.elements cset)
...@@ -528,6 +588,11 @@ let () = ...@@ -528,6 +588,11 @@ let () =
(* --- Request getProbeInfo --- *) (* --- Request getProbeInfo --- *)
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
let is_reachable = function
| Stmt (_, stmt) -> Results.is_reachable stmt
| Pre kf -> Results.is_called kf
| Initial -> Results.is_reachable_kinstr Kglobal
let () = let () =
let getProbeInfo = Request.signature ~input:(module Jmarker) () in let getProbeInfo = Request.signature ~input:(module Jmarker) () in
let set_evaluable = Request.result getProbeInfo let set_evaluable = Request.result getProbeInfo
...@@ -539,9 +604,6 @@ let () = ...@@ -539,9 +604,6 @@ let () =
and set_stmt = Request.result_opt getProbeInfo and set_stmt = Request.result_opt getProbeInfo
~name:"stmt" ~descr:(Md.plain "Probe statement") ~name:"stmt" ~descr:(Md.plain "Probe statement")
(module Jstmt) (module Jstmt)
and set_rank = Request.result getProbeInfo
~name:"rank" ~descr:(Md.plain "Probe statement rank")
~default:0 (module Jint)
and set_effects = Request.result getProbeInfo and set_effects = Request.result getProbeInfo
~name:"effects" ~descr:(Md.plain "Effectfull statement") ~name:"effects" ~descr:(Md.plain "Effectfull statement")
~default:false (module Jbool) ~default:false (module Jbool)
...@@ -549,27 +611,30 @@ let () = ...@@ -549,27 +611,30 @@ let () =
~name:"condition" ~descr:(Md.plain "Conditional statement") ~name:"condition" ~descr:(Md.plain "Conditional statement")
~default:false (module Jbool) ~default:false (module Jbool)
in in
let set_probe rq pp p s = let set_probe rq pp p eval_point =
let computed = Analysis.is_computed () in let computed = Analysis.is_computed () in
let reachable = Results.is_reachable s in let reachable = is_reachable eval_point in
set_evaluable rq (computed && reachable); set_evaluable rq (computed && reachable);
set_code rq (Some (Pretty_utils.to_string pp p)) ; set_code rq (Some (Pretty_utils.to_string pp p));
set_stmt rq (Some s) ; set_stmt rq (match eval_point with Stmt (_, s) -> Some s | _ -> None);
set_rank rq (Ranking.stmt s) ;
let on_steps = function let on_steps = function
| `Here -> () | `Here -> ()
| `Then _ | `Else _ -> set_condition rq true | `Then _ | `Else _ -> set_condition rq true
| `After -> set_effects rq true | `After -> set_effects rq true
in List.iter on_steps (next_steps s) in
List.iter on_steps (next_steps eval_point)
in in
Request.register_sig ~package getProbeInfo Request.register_sig ~package getProbeInfo
~kind:`GET ~name:"getProbeInfo" ~kind:`GET ~name:"getProbeInfo"
~descr:(Md.plain "Probe informations") ~descr:(Md.plain "Probe informations")
begin fun rq marker -> begin fun rq marker ->
match probe marker with match probe marker with
| Some (Plval (l, s)) -> set_probe rq Printer.pp_lval l s
| Some (Pexpr (e, s)) -> set_probe rq Printer.pp_exp e s
| None -> set_evaluable rq false | None -> set_evaluable rq false
| Some (term, eval_point) ->
match term with
| Plval l -> set_probe rq Printer.pp_lval l eval_point
| Pexpr e -> set_probe rq Printer.pp_exp e eval_point
| Ppred p -> set_probe rq Printer.pp_predicate p eval_point
end end
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
......
...@@ -138,6 +138,11 @@ let create_new_var name typ = ...@@ -138,6 +138,11 @@ let create_new_var name typ =
let is_const_write_invalid typ = Cil.typeHasQualifier "const" typ let is_const_write_invalid typ = Cil.typeHasQualifier "const" typ
let find_return_var kf =
match (Kernel_function.find_return kf).skind with
| Return (Some ({enode = Lval ((Var vi, NoOffset))}), _) -> Some vi
| _ | exception Kernel_function.No_Statement -> None
(* Find if a postcondition contains [\result] *) (* Find if a postcondition contains [\result] *)
class postconditions_mention_result = object class postconditions_mention_result = object
inherit Visitor.frama_c_inplace inherit Visitor.frama_c_inplace
......
...@@ -72,6 +72,10 @@ val is_const_write_invalid: typ -> bool ...@@ -72,6 +72,10 @@ val is_const_write_invalid: typ -> bool
(** Detect that the type is const, and that option [-global-const] is set. In (** Detect that the type is const, and that option [-global-const] is set. In
this case, we forbid writing in a l-value that has this type. *) this case, we forbid writing in a l-value that has this type. *)
val find_return_var: kernel_function -> varinfo option
(** Returns the varinfo returned by the given function.
Returns None if the function returns void or has no return statement. *)
val postconditions_mention_result: Cil_types.funspec -> bool val postconditions_mention_result: Cil_types.funspec -> bool
(** Does the post-conditions of this specification mention [\result]? *) (** Does the post-conditions of this specification mention [\result]? *)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment