From 722ff561aaea34ee5f17ec4ba1c64222e7ca3422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Thu, 25 Jul 2024 17:21:12 +0200 Subject: [PATCH] [Eva] In transfer_logic, reworks functions that emit messages and statuses. --- src/plugins/eva/engine/transfer_logic.ml | 163 +++++++++++------------ 1 file changed, 77 insertions(+), 86 deletions(-) diff --git a/src/plugins/eva/engine/transfer_logic.ml b/src/plugins/eva/engine/transfer_logic.ml index 5dc4ddfdc11..fc5ed9085cc 100644 --- a/src/plugins/eva/engine/transfer_logic.ml +++ b/src/plugins/eva/engine/transfer_logic.ml @@ -27,7 +27,26 @@ open Eval let ignore_predicate named_pred = List.exists (fun tag -> tag = "no_eva") named_pred.Cil_types.pred_name -(* -------------------------- Message emission ------------------------------ *) +let create_conjunction l= + let loc = match l with + | [] -> None + | p :: _ -> Some (Logic_const.pred_of_id_pred p).pred_loc + in + Logic_const.(List.fold_right (fun p1 p2 -> pand ?loc (p1, p2)) (List.map pred_of_id_pred l) ptrue) + +let ip_from_precondition kf call_ki b pre = + let ip_precondition = Property.ip_of_requires kf Kglobal b pre in + match call_ki with + | Kglobal -> (* status of the main function. We update the global + status, and pray that there is no recursion. + TODO: check what the WP does.*) + ip_precondition + | Kstmt stmt -> + (* choose the copy of the precondition on the call point [stmt]. *) + Statuses_by_call.setup_precondition_proxy kf ip_precondition; + Statuses_by_call.precondition_at_call kf ip_precondition stmt + +(* --------------------- Message and status emission ------------------------ *) (* The function that puts statuses on pre- and post-conditions is essentially agnostic as to which kind of property it operates on. However, the messages @@ -60,15 +79,15 @@ let post_kind kf = else PostLeaf else PostBody -let conv_status = function - | Alarmset.False -> Property_status.False_if_reachable; - | Alarmset.True -> Property_status.True; - | Alarmset.Unknown -> Property_status.Dont_know - let emit_status ppt status = - if status = Property_status.False_if_reachable then begin + let status = + match status with + | Alarmset.False -> Property_status.False_if_reachable; + | Alarmset.True -> Property_status.True; + | Alarmset.Unknown -> Property_status.Dont_know + in + if status = Property_status.False_if_reachable then Red_statuses.add_red_property (Property.get_kinstr ppt) ppt; - end; Property_status.emit ~distinct:true Eva_utils.emitter ~hyps:[] ppt status (* Display the message as result/warning depending on [status] *) @@ -111,7 +130,7 @@ let pp_predicate behavior kind fmt named_pred = in Format.fprintf fmt "%a%a" pp_p_kind kind pp_predicate named_pred -let emit_message_and_status kind kf behavior ~active ~empty property named_pred status = +let emit_contract_status kind kf behavior ~active ~empty property named_pred status = let pp_predicate = pp_predicate behavior kind in let source = fst (Property.location property) in match kind with @@ -124,34 +143,51 @@ let emit_message_and_status kind kf behavior ~active ~empty property named_pred Alarmset.Status.pretty status (if active then (fun _ -> ()) else behavior_inactive) Eva_utils.pp_callstack; - emit_status property (conv_status status); + emit_status property status; | Postcondition postk -> (* Do not emit a status for leaf functions or builtins. Otherwise, we would overwrite the "considered valid" status of the kernel. *) if emit_postcond_status postk - then emit_status property (conv_status status) + then emit_status property status | Assumes -> (* No statuses are emitted for 'assumes' clauses, and for the moment we do not emit text either *) () -let create_conjunction l= - let loc = match l with - | [] -> None - | p :: _ -> Some (Logic_const.pred_of_id_pred p).pred_loc +let pp_code_annot fmt ca = + match ca.annot_content with + | AAssert (_,{ tp_kind; tp_statement }) -> + let kind = Cil_printer.name_of_assert tp_kind in + Format.fprintf fmt "%s%a" kind Description.pp_named tp_statement + | AInvariant (_, _, { tp_statement }) -> + Format.fprintf fmt "loop invariant%a" Description.pp_named tp_statement + | AExtended (_, _, extension) -> + Format.fprintf fmt "%s annotation" extension.ext_name; + | APragma _ | AVariant _ | AAssigns _ | AAllocation _ | AStmtSpec _ -> + assert false (* currently not treated by Eva *) + +(* location of the given code annotation. If unknown, use the location of the + statement instead. *) +let code_annotation_loc stmt code_annot = + match Cil_datatype.Code_annotation.loc code_annot with + | Some loc when not (Cil_datatype.Location.(equal loc unknown)) -> loc + | _ -> Cil_datatype.Stmt.loc stmt + +let emit_code_annot_status ~reduce ~empty kf stmt code_annot status = + let source, _ = code_annotation_loc stmt code_annot in + let ips = Property.ip_of_code_annot kf stmt code_annot in + List.iter (fun p -> emit_status p status) ips; + let message = + match status with + | Alarmset.Unknown -> "unknown" + | Alarmset.True -> "valid" + | Alarmset.False -> + "invalid" ^ (if reduce then " (stopping propagation)" else "") in - Logic_const.(List.fold_right (fun p1 p2 -> pand ?loc (p1, p2)) (List.map pred_of_id_pred l) ptrue) + let prefix = if empty then "no state left, " else "" in + msg_status status ~once:true ~source + "%s%a got status %s." prefix pp_code_annot code_annot message -let ip_from_precondition kf call_ki b pre = - let ip_precondition = Property.ip_of_requires kf Kglobal b pre in - match call_ki with - | Kglobal -> (* status of the main function. We update the global - status, and pray that there is no recursion. - TODO: check what the WP does.*) - ip_precondition - | Kstmt stmt -> - (* choose the copy of the precondition on the call point [stmt]. *) - Statuses_by_call.setup_precondition_proxy kf ip_precondition; - Statuses_by_call.precondition_at_call kf ip_precondition stmt +(* --------------------- Process inactive behaviors ------------------------- *) (* Emits informative messages about inactive behaviors, and emits a valid status for requires and ensures that have not been evaluated. *) @@ -163,14 +199,14 @@ let process_inactive_behavior kf call_ki behavior = emitted := true; if emit_postcond_status (post_kind kf) then let ip = Property.ip_of_ensures kf Kglobal behavior post in - emit_status ip Property_status.True; + emit_status ip Alarmset.True; end ) behavior.b_post_cond; List.iter (fun pre -> if pre.ip_content.tp_kind <> Admit then begin emitted := true; let ip = ip_from_precondition kf call_ki behavior pre in - emit_status ip Property_status.True; + emit_status ip Alarmset.True; end ) behavior.b_requires; if !emitted then @@ -192,7 +228,7 @@ let process_inactive_postconds kf inactive_bhvs = emitted := true; if emit_postcond_status (post_kind kf) then let ip = Property.ip_of_ensures kf Kglobal b post in - emit_status ip Property_status.True; + emit_status ip Alarmset.True; end ) b.b_post_cond; if !emitted then @@ -392,7 +428,7 @@ module Make the pre- and post-states. *) let eval_and_reduce kf behavior active kind ips states build_prop build_env = let limit = Eva_utils.get_slevel kf in - let emit = emit_message_and_status kind kf behavior ~active in + let emit = emit_contract_status kind kf behavior ~active in let aux_pred states pred = let pr = Logic_const.pred_of_id_pred pred in let record = pred.ip_content.tp_kind <> Admit in @@ -534,30 +570,12 @@ module Make let assumes = create_conjunction behavior.b_assumes in Domain.evaluate_predicate pre_env state assumes - let code_annotation_text ca = - match ca.annot_content with - | AAssert (_,{tp_kind}) -> Cil_printer.name_of_assert tp_kind - | AInvariant _ -> "loop invariant" - | APragma _ | AVariant _ | AAssigns _ | AAllocation _ | AStmtSpec _ - | AExtended _ -> - assert false (* currently not treated by Value *) - - (* location of the given code annotation. If unknown, use the location of the - statement instead. *) - let code_annotation_loc ca stmt = - match Cil_datatype.Code_annotation.loc ca with - | Some loc when not (Cil_datatype.Location.(equal loc unknown)) -> loc - | _ -> Cil_datatype.Stmt.loc stmt - (* Reduce the given states according to the given code annotations. If [record] is true, update the proof state of the code annotation. DO NOT PASS record=false unless you know what your are doing *) let interp_annot ~limit ~record kf ab stmt code_annot ~initial_state states = - let ips = Property.ip_of_code_annot kf stmt code_annot in - let source, _ = code_annotation_loc code_annot stmt in let aux_interp ~record ~reduce code_annot behav p = - let text = code_annotation_text code_annot in let in_behavior = match behav with | [] -> `True @@ -573,36 +591,13 @@ module Make match in_behavior with | `False -> states | `True | `Unknown as in_behavior -> - let emit status = - let change_status st = List.iter (fun p -> emit_status p st) ips in - let message = - match status, in_behavior with - | Alarmset.Unknown, _ -> - change_status Property_status.Dont_know; - "unknown" - | Alarmset.True, _ -> - change_status Property_status.True; - "valid" - | Alarmset.False, `True -> - change_status Property_status.False_if_reachable; - "invalid" ^ (if reduce then " (stopping propagation)" else "") - | Alarmset.False, `Unknown -> - change_status Property_status.False_if_reachable; - "invalid" - in - msg_status status ~once:true ~source - "%s%a got status %s." text Description.pp_named p message - in + (* No reduction if the behavior might be inactive. *) + let reduce = reduce && in_behavior = `True in + let emit = emit_code_annot_status ~reduce ~empty:false kf stmt in let reduce_state here res accstateset = - match res, in_behavior with - | _, `Unknown -> - (* Cannot conclude because behavior might be inactive *) - States.add here accstateset - - | Alarmset.False, `True -> (* Dead/invalid branch *) - accstateset - - | (Alarmset.Unknown | Alarmset.True), `True -> + match res with + | Alarmset.False -> accstateset (* Dead/invalid branch *) + | Alarmset.Unknown | Alarmset.True -> let env = here_env ~pre:initial_state ~here in (* Reduce by p if it is a disjunction, or if it did not evaluate to True *) @@ -618,7 +613,7 @@ module Make let env = here_env ~pre:initial_state ~here in let res = Domain.evaluate_predicate env here p in (* if [record] holds, emit kernel status and print a message *) - if record then emit res; + if record then emit code_annot res; (* if [reduce] holds, reduce the state. *) if reduce then reduce_state here res accstateset else accstateset) states States.empty @@ -631,13 +626,9 @@ module Make if ignore_predicate p then states else if States.is_empty states then ( - if record then begin - let text = code_annotation_text code_annot in - List.iter (fun p -> emit_status p Property_status.True) ips; - msg_status Alarmset.True ~once:true ~source - "no state left, %s%a got status valid." - text Description.pp_named p; - end; + if record then + emit_code_annot_status ~reduce:true ~empty:true + kf stmt code_annot Alarmset.True; states ) else aux_interp ~record ~reduce code_annot behav p -- GitLab