From 4f9b2e5319370237fb649d62a88117e3b6781bb0 Mon Sep 17 00:00:00 2001 From: Thibault Martin <thi.martin.pro@pm.me> Date: Wed, 26 Jul 2023 14:08:32 +0200 Subject: [PATCH] Add default requires for prototypes in safe mode --- src/kernel_internals/typing/populate_spec.ml | 118 ++++++++++++------- src/kernel_services/ast_data/property.ml | 14 ++- 2 files changed, 84 insertions(+), 48 deletions(-) diff --git a/src/kernel_internals/typing/populate_spec.ml b/src/kernel_internals/typing/populate_spec.ml index 3164f227db5..76f20f9e9b5 100644 --- a/src/kernel_internals/typing/populate_spec.ml +++ b/src/kernel_internals/typing/populate_spec.ml @@ -28,6 +28,7 @@ type mode = ACSL | Safe | Frama_C | Other of string type config = { exits: mode; assigns: mode; + requires: mode; allocates: mode; terminates: mode; } @@ -37,12 +38,21 @@ type 'a result = Kept | Generated of 'a let default = Cil.default_behavior_name let emitter = - Emitter.create "gen" - [ Funspec ; Property_status ] ~correctness:[] ~tuning:[] + Emitter.create "PopulateSpec" + [ Funspec; Property_status ] ~correctness:[] ~tuning:[] let emit_status status ppt = Property_status.emit emitter ~hyps:[] ppt status +let completes_generic (type clause) completes table = + let exception Ok of clause list in + let collect l b = Hashtbl.find table b :: l in + let collect bhvs = + try let r = List.fold_left collect [] bhvs in raise (Ok r) + with Not_found -> () + in + try List.iter collect completes; None with Ok l -> Some l + module type Generator = sig @@ -104,17 +114,10 @@ struct let exits = List.filter (fun (k, _ ) -> Exits = k) b.b_post_cond in if exits <> [] then Hashtbl.add table b.b_name exits in - List.iter iter spec.spec_behavior ; + List.iter iter spec.spec_behavior; table - let completes completes table = - let exception Ok of clause list in - let collect l b = Hashtbl.find table b :: l in - let collect bhvs = - try let r = List.fold_left collect [] bhvs in raise (Ok r) - with Not_found -> () - in - try List.iter collect completes ; None with Ok l -> Some l + let completes = completes_generic let acsl_default () = [] @@ -165,24 +168,13 @@ struct let collect_behaviors spec = let table = Hashtbl.create 17 in - let iter { b_name ; b_assigns } = + let iter { b_name; b_assigns } = if b_assigns <> WritesAny then Hashtbl.add table b_name b_assigns in - List.iter iter spec.spec_behavior ; + List.iter iter spec.spec_behavior; table - let completes (completes : string list list) (table : behaviors) = - let assigns = function - | WritesAny -> raise Not_found - | Writes l -> Writes l - in - let exception Ok of assigns list in - let collect l b = (assigns @@ Hashtbl.find table b) :: l in - let collect bhvs = - try let r = List.fold_left collect [] bhvs in raise (Ok r) - with Not_found -> () - in - try List.iter collect completes ; None with Ok l -> Some l + let completes = completes_generic let acsl_default () = WritesAny @@ -257,6 +249,54 @@ struct end +module Requires_generator = +struct + + type clause = identified_predicate list + type behaviors = (string, clause) Hashtbl.t + + let has_behavior name behaviors = + Hashtbl.mem behaviors name + + let collect_behaviors spec = + let table = Hashtbl.create 17 in + let iter { b_name; b_requires } = + if b_requires <> [] then Hashtbl.add table b_name b_requires + in + List.iter iter spec.spec_behavior; + table + + let completes = completes_generic + + let acsl_default () = [] + + let safe_default has_body = + if has_body + then [] + else [ Logic_const.(new_predicate pfalse) ] + + let frama_c_default _ = + acsl_default () + + let combine_default (clauses : clause list) = + let flatten_require clause = + List.map (fun p -> p.ip_content.tp_statement) clause + |> List.sort_uniq Cil_datatype.PredicateStructEq.compare + |> Logic_const.pands + in + let preds = + List.map flatten_require clauses + |> Logic_const.pors + in + [ Logic_const.new_predicate preds ] + + let custom_default _mode _kf _spec = + acsl_default () + + let emit _ _ _ _ = () + +end + module Allocates_generator = struct type clause = allocation @@ -267,24 +307,13 @@ struct let collect_behaviors spec = let table = Hashtbl.create 17 in - let iter { b_name ; b_allocation } = + let iter { b_name; b_allocation } = if b_allocation <> FreeAllocAny then Hashtbl.add table b_name b_allocation in - List.iter iter spec.spec_behavior ; + List.iter iter spec.spec_behavior; table - let completes (completes : string list list) (table : behaviors) = - let allocation = function - | FreeAllocAny -> raise Not_found - | alloc -> alloc - in - let exception Ok of allocation list in - let collect l b = (allocation @@ Hashtbl.find table b) :: l in - let collect bhvs = - try let r = List.fold_left collect [] bhvs in raise (Ok r) - with Not_found -> () - in - try List.iter collect completes ; None with Ok l -> Some l + let completes = completes_generic let acsl_default () = FreeAlloc([],[]) @@ -359,7 +388,7 @@ struct acsl_default () let combine_default _ = - acsl_default () + assert false let custom_default _mode _kf _spec = acsl_default () @@ -386,6 +415,7 @@ end module Exits = Make(Exits_generator) module Assigns = Make(Assigns_generator) +module Requires = Make(Requires_generator) module Allocates = Make(Allocates_generator) module Terminates = Make(Terminates_generator) @@ -401,6 +431,7 @@ let get_mode = function let build_config mode = { exits = mode; assigns = mode; + requires = mode; allocates = mode; terminates = mode; } @@ -416,6 +447,7 @@ let get_config () = match k with | "exits" -> {conf with exits = mode} | "assigns" -> {conf with assigns = mode} + | "requires" -> {conf with requires = mode} | "allocates" -> {conf with allocates = mode} | "terminates" -> {conf with terminates = mode} | s -> @@ -430,6 +462,7 @@ let do_populate kf original_spec = let exits = Exits.get_default config.exits kf original_spec in let assigns = Assigns.get_default config.assigns kf original_spec in + let requires = Requires.get_default config.requires kf original_spec in let allocates = Allocates.get_default config.allocates kf original_spec in let terminates = Terminates.get_default config.terminates kf original_spec in @@ -441,6 +474,7 @@ let do_populate kf original_spec = let bhv = Cil.mk_behavior () in let bhv = { bhv with b_post_cond = generated bhv.b_post_cond exits } in let bhv = { bhv with b_assigns = generated bhv.b_assigns assigns } in + let bhv = { bhv with b_requires = generated bhv.b_requires requires } in let bhv = { bhv with b_allocation = generated bhv.b_allocation allocates } in let spec = Cil.empty_funspec () in @@ -468,8 +502,8 @@ let () = Ast.add_linked_state Is_populated.self let populate_funspec kf spec = if Is_populated.mem kf then false else begin - do_populate kf spec ; - Is_populated.add kf () ; + do_populate kf spec; + Is_populated.add kf (); true end diff --git a/src/kernel_services/ast_data/property.ml b/src/kernel_services/ast_data/property.ml index 95c554429b7..8a10e8ec185 100644 --- a/src/kernel_services/ast_data/property.ml +++ b/src/kernel_services/ast_data/property.ml @@ -1351,12 +1351,14 @@ let ip_assigns_of_code_annot kf st ca = match ca.annot_content with let ip_from_of_code_annot kf st ca = match ca.annot_content with | AAssigns(_,WritesAny) -> [] | AAssigns (_,Writes l) -> - let treat_from acc (out, froms) = match froms with FromAny -> acc - | From _ -> - let ip = - Option.get (ip_of_from kf st (Id_loop ca) (out, froms)) - in - ip::acc + let treat_from acc (out, froms) = + match froms with + | FromAny -> acc + | From _ -> + let ip = + Option.get (ip_of_from kf st (Id_loop ca) (out, froms)) + in + ip::acc in List.fold_left treat_from [] l | _ -> [] -- GitLab