diff --git a/headers/header_spec.txt b/headers/header_spec.txt index 9c669cda9390d35e43e048e6019ba9aa82c09c84..c93566dd8f25aa7f4af928fcf2b80a4f224dd72e 100644 --- a/headers/header_spec.txt +++ b/headers/header_spec.txt @@ -945,6 +945,8 @@ src/plugins/occurrence/register_gui.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/occurrence/register_gui.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/basic_blocks.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/basic_blocks.mli: CEA_LGPL_OR_PROPRIETARY +src/plugins/instantiate/global_context.ml: CEA_LGPL_OR_PROPRIETARY +src/plugins/instantiate/global_context.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/Instantiate.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/instantiator_builder.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/instantiator_builder.mli: CEA_LGPL_OR_PROPRIETARY @@ -958,6 +960,8 @@ src/plugins/instantiate/stdlib/free.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/stdlib/free.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/stdlib/malloc.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/stdlib/malloc.mli: CEA_LGPL_OR_PROPRIETARY +src/plugins/instantiate/string/mem_utils.ml: CEA_LGPL_OR_PROPRIETARY +src/plugins/instantiate/string/mem_utils.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/string/memcmp.ml: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/string/memcmp.mli: CEA_LGPL_OR_PROPRIETARY src/plugins/instantiate/string/memcpy.ml: CEA_LGPL_OR_PROPRIETARY diff --git a/src/plugins/instantiate/Instantiate.mli b/src/plugins/instantiate/Instantiate.mli index 061723344f1df682af0b1900e95324f0cc451b5e..4444dd5d95bae406b65c2def46efcd16145479da 100644 --- a/src/plugins/instantiate/Instantiate.mli +++ b/src/plugins/instantiate/Instantiate.mli @@ -41,19 +41,20 @@ module Instantiator_builder: sig (** Name of the implemented instantiator function *) val function_name: string - (** [well_typed_call ret args] must return true if and only if the + (** [well_typed_call ret fct args] must return true if and only if the corresponding call is well typed in the sens that the generator can produce a function override for the corresponding return value and parameters, according to their types and/or values. *) - val well_typed_call: lval option -> exp list -> bool + val well_typed_call: lval option -> varinfo -> exp list -> bool - (** [key_from_call ret args] must return an identifier for the corresponding - call. [key_from_call ret1 args1] and [key_from_call ret2 args2] must equal - if and only if the same override function can be used for both call. Any - call for which [well_typed_call] returns true must be able to give a key. + (** [key_from_call ret fct args] must return an identifier for the + corresponding call. [key_from_call ret1 fct1 args1] and + [key_from_call ret2 fct2 args2] must equal if and only if the same + override function can be used for both call. Any call for which + [well_typed_call] returns true must be able to give a key. *) - val key_from_call: lval option -> exp list -> override_key + val key_from_call: lval option -> varinfo -> exp list -> override_key (** [retype_args key args] must returns a new argument list compatible with the function identified by [override_key]. [args] is the list of arguments @@ -99,3 +100,13 @@ module Transform: sig *) val register: (module Instantiator_builder.Generator_sig) -> unit end + +module Global_context:sig + (** [get_variable name f] searches for an existing variable [name]. If this + variable does not exists, it is created using [f]. + + The obtained varinfo does not need to be registered, nor [f] needs to + perform the registration, it will be done by the transformation. + *) + val get_variable: string -> (unit -> varinfo) -> varinfo +end diff --git a/src/plugins/instantiate/Makefile.in b/src/plugins/instantiate/Makefile.in index 144f5c7128e6ee8400c61832f24d3ae069027a0a..8635d3bace9d9077ef18361548a18fc660a56aa2 100644 --- a/src/plugins/instantiate/Makefile.in +++ b/src/plugins/instantiate/Makefile.in @@ -30,6 +30,7 @@ FRAMAC_LIBDIR :=$(shell frama-c-config -print-libpath) endif SRC_STRING:= \ + mem_utils \ memcmp \ memcpy \ memmove \ @@ -55,7 +56,9 @@ PLUGIN_EXTRA_DIRS:=\ stdlib PLUGIN_CMI := PLUGIN_CMO := \ - options basic_blocks instantiator_builder transform register \ + options basic_blocks \ + global_context instantiator_builder \ + transform register \ $(SRC_STRING) \ $(SRC_STDLIB) diff --git a/src/plugins/instantiate/global_context.ml b/src/plugins/instantiate/global_context.ml new file mode 100644 index 0000000000000000000000000000000000000000..9791a78d529581153916776dd28b906b02c35232 --- /dev/null +++ b/src/plugins/instantiate/global_context.ml @@ -0,0 +1,90 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2020 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +module Table = Datatype.String.Hashtbl + +let varinfos = Table.create 13 +let logic_functions = Table.create 13 +let axiomatics = Table.create 13 + +let get_variable name make = + if Table.mem varinfos name then Table.find varinfos name + else begin + try Globals.Vars.find_from_astinfo name VGlobal + with Not_found -> + let vi = make () in + Table.add varinfos name vi ; + vi + end + +let get_logic_function name make = + if Table.mem logic_functions name then Table.find logic_functions name + else begin + match Logic_env.find_all_logic_functions name with + | [] -> + let li = make () in + Table.add logic_functions name li ; + Logic_utils.add_logic_function li ; + li + | [x] -> x + | _ :: _ -> Options.not_yet_implemented "Logic function overloading" + end + +let in_axiomatic_functions = Table.create 13 + +let get_logic_function_in_axiomatic name make = + if Table.mem in_axiomatic_functions name then + Table.find in_axiomatic_functions name + else begin + let make_then_find name = + let open Cil_types in + let (ax_name, ax_list), functions = make () in + List.iter + (fun f -> + Table.add in_axiomatic_functions f.l_var_info.lv_name f ; + Logic_utils.add_logic_function f) + functions ; + Table.add axiomatics ax_name ax_list ; + Table.find in_axiomatic_functions name + in + try match Logic_env.find_all_logic_functions name with + | [] -> make_then_find name + | [x] -> x + | _ :: _ -> Options.not_yet_implemented "Logic function overloading" + with Not_found -> + Options.fatal "Failed to build %s" name + end + +let clear () = Table.clear varinfos + +let globals loc = + let open Cil_types in + let l = [] in + let l = + Table.fold (fun _ x l -> GVarDecl(x, loc) :: l) varinfos l + in + let annot x loc = GAnnot(x, loc) in + let fun_or_pred x loc = annot (Dfun_or_pred (x, loc)) loc in + let axiomatic name list loc = annot(Daxiomatic(name, list, [], loc)) loc in + let l = Table.fold (fun _ x l -> fun_or_pred x loc :: l) logic_functions l in + let l = Table.fold (fun n x l -> axiomatic n x loc :: l) axiomatics l in + l diff --git a/src/plugins/instantiate/global_context.mli b/src/plugins/instantiate/global_context.mli new file mode 100644 index 0000000000000000000000000000000000000000..9a1456ff0bb26db8834f8857a883749d52e91b8b --- /dev/null +++ b/src/plugins/instantiate/global_context.mli @@ -0,0 +1,65 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2020 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +open Cil_types + +(** The purpose of this module global definitions when it is needed by + instantiation modules. +*) + +(** [get_variable name f] searches for an existing variable [name]. If this + variable does not exists, it is created using [f]. + + The obtained varinfo does not need to be registered, nor [f] needs to + perform the registration, it will be done by the transformation. +*) +val get_variable: string -> (unit -> varinfo) -> varinfo + +(** [get_logic_function name f] searches for an existing logic function [name]. + If this function does not exists, it is created using [f]. If the logic + function must be part of an axiomatic block **DO NOT** use this function, + use [get_logic_function_in_axiomatic]. + + Note that function overloading is not supported. +*) +val get_logic_function: string -> (unit -> logic_info) -> logic_info + +(** [get_logic_function_in_axiomatic name f] searches for an existing logic + function [name]. If this function does not exists, an axiomatic definition + is created using [f]. + + [f] must return: + - the axiomatic in a form [name, list of the defintions (incl. functions)] + - all functions that are part of the axiomatic definition + + Note that function overloading is not supported. +*) +val get_logic_function_in_axiomatic: + string -> + (unit -> (string * global_annotation list) * logic_info list) -> + logic_info + +(** Clears internal tables *) +val clear: unit -> unit + +(** Creates a list of global for the elements that have been created *) +val globals: location -> global list diff --git a/src/plugins/instantiate/instantiator_builder.ml b/src/plugins/instantiate/instantiator_builder.ml index df9028d122de56f183632d9571c2f3e3056ec14c..74242ed7bb5f1a50f2fbde264954abda3404141e 100644 --- a/src/plugins/instantiate/instantiator_builder.ml +++ b/src/plugins/instantiate/instantiator_builder.ml @@ -28,8 +28,8 @@ module type Generator_sig = sig type override_key = Hashtbl.key val function_name: string - val well_typed_call: lval option -> exp list -> bool - val key_from_call: lval option -> exp list -> override_key + val well_typed_call: lval option -> varinfo -> exp list -> bool + val key_from_call: lval option -> varinfo -> exp list -> override_key val retype_args: override_key -> exp list -> exp list val args_for_original: override_key -> exp list -> exp list val generate_prototype: override_key -> (string * typ) @@ -41,15 +41,14 @@ module type Instantiator = sig type override_key val function_name: string - val well_typed_call: lval option -> exp list -> bool - val key_from_call: lval option -> exp list -> override_key + val well_typed_call: lval option -> varinfo -> exp list -> bool + val key_from_call: lval option -> varinfo -> exp list -> override_key val retype_args: override_key -> exp list -> exp list val get_override: override_key -> fundec val get_kfs: unit -> kernel_function list - val mark_as_computed: ?project:Project.t -> unit -> unit + val clear: unit -> unit end - let build_body caller callee args_generator = let open Extlib in let loc = Cil_datatype.Location.unknown in @@ -68,12 +67,13 @@ let build_body caller callee args_generator = module Make_instantiator (G: Generator_sig) = struct include G module Enabled = Options.NewInstantiator (G) - module Cache = State_builder.Hashtbl (G.Hashtbl) (Cil_datatype.Fundec) - (struct - let size = 5 - let dependencies = [] - let name = "Instantiator." ^ G.function_name - end) + module Cache = struct + let tbl = G.Hashtbl.create 13 + let find = G.Hashtbl.find tbl + let add = G.Hashtbl.add tbl + let fold f = G.Hashtbl.fold f tbl + let clear () = G.Hashtbl.clear tbl + end let make_fundec key = let open Globals.Functions in @@ -113,5 +113,6 @@ module Make_instantiator (G: Generator_sig) = struct let get_kfs () = Cache.fold (fun _ fd l -> Globals.Functions.get fd.svar :: l) [] - let mark_as_computed = Cache.mark_as_computed + let clear () = + Cache.clear () end diff --git a/src/plugins/instantiate/instantiator_builder.mli b/src/plugins/instantiate/instantiator_builder.mli index e2432608275499398adeb83d13636fb8ea7f2146..b0eb2f79fcf975b1957079beed9ac29d32c14e6d 100644 --- a/src/plugins/instantiate/instantiator_builder.mli +++ b/src/plugins/instantiate/instantiator_builder.mli @@ -40,19 +40,20 @@ module type Generator_sig = sig (** Name of the implemented function *) val function_name: string - (** [well_typed_call ret args] must return true if and only if the + (** [well_typed_call ret fct args] must return true if and only if the corresponding call is well typed in the sens that the generator can produce a function override for the corresponding return value and parameters, according to their types and/or values. *) - val well_typed_call: lval option -> exp list -> bool + val well_typed_call: lval option -> varinfo -> exp list -> bool - (** [key_from_call ret args] must return an identifier for the corresponding - call. [key_from_call ret1 args1] and [key_from_call ret2 args2] must equal - if and only if the same override function can be used for both call. Any - call for which [well_typed_call] returns true must be able to give a key. + (** [key_from_call ret fct args] must return an identifier for the + corresponding call. [key_from_call ret1 fct1 args1] and + [key_from_call ret2 fct2 args2] must equal if and only if the same + override function can be used for both call. Any call for which + [well_typed_call] returns true must be able to give a key. *) - val key_from_call: lval option -> exp list -> override_key + val key_from_call: lval option -> varinfo -> exp list -> override_key (** [retype_args key args] must returns a new argument list compatible with the function identified by [override_key]. [args] is the list of arguments @@ -105,9 +106,9 @@ module type Instantiator = sig (** Same as [Generator_sig.override_key] *) val function_name: string (** Same as [Generator_sig.override_key] *) - val well_typed_call: lval option -> exp list -> bool + val well_typed_call: lval option -> varinfo -> exp list -> bool (** Same as [Generator_sig.override_key] *) - val key_from_call: lval option -> exp list -> override_key + val key_from_call: lval option -> varinfo -> exp list -> override_key (** Same as [Generator_sig.override_key] *) val retype_args: override_key -> exp list -> exp list @@ -123,10 +124,9 @@ module type Instantiator = sig *) val get_kfs: unit -> kernel_function list - (** [mark_as_computed ?project ()] applies the [mark_as_computed] on the - internal table. + (** [clear ()] clears the internal table of the instantiator. *) - val mark_as_computed: ?project:Project.t -> unit -> unit + val clear: unit -> unit end (** Generates a [Instantiator] from a [Generator_sig] adding all necessary stuff for diff --git a/src/plugins/instantiate/stdlib/basic_alloc.ml b/src/plugins/instantiate/stdlib/basic_alloc.ml index 41679ef1d11045cfaef1aff637ec7b4f1de63409..a35a97b53e37d96e97149e0bb851c4db758cac6c 100644 --- a/src/plugins/instantiate/stdlib/basic_alloc.ml +++ b/src/plugins/instantiate/stdlib/basic_alloc.ml @@ -47,10 +47,56 @@ let valid_size ?loc typ size = in new_predicate { p with pred_name = ["correct_size"] } +let heap_status () = + let name = "__fc_heap_status" in + let make () = + let vi = Cil.makeVarinfo ~ghost:true true false name Cil.intType in + vi.vstorage <- Extern ; + vi + in + let vi = Global_context.get_variable name make in + Basic_blocks.cvar_to_tvar vi + +let make_is_allocable () = + let name = "is_allocable" in + { + l_var_info = Cil_const.make_logic_var_global name (Ctype Cil.voidType) ; + l_type = None ; + l_tparams = []; + l_labels = [FormalLabel("L")]; + l_profile = [Cil_const.make_logic_var_formal "i" Linteger] ; + l_body = LBreads [new_identified_term (heap_status())]; + } + +let make_axiomatic_is_allocable loc () = + let is_allocable = make_is_allocable () in + let lv_i = Cil_const.make_logic_var_quant "i" Linteger in + let t_i = tvar lv_i in + let zero = tinteger 0 in + let max = + tinteger + (Integer.to_int + (Cil.max_unsigned_number (Cil.bitsSizeOf (size_t ())))) + in + let label = FormalLabel("L") in + let cond = pand (prel (Rlt, t_i, zero), prel (Rgt, t_i, max)) in + let app = pnot (papp (is_allocable,[label],[t_i])) in + let prop = pforall ([lv_i], pimplies (cond, app)) in + let gfun = Dfun_or_pred(is_allocable, loc) in + let axiom = Dlemma("never_allocable", true, [label],[],prop,[], loc) in + ("dynamic_allocation", [gfun ; axiom]), [is_allocable] + +let get_is_allocable loc = + Global_context.get_logic_function_in_axiomatic + "is_allocable" (make_axiomatic_is_allocable loc) + let pis_allocable ?loc size = - let is_allocable = Logic_env.find_all_logic_functions "is_allocable" in - let is_allocable = as_singleton is_allocable in - papp ?loc (is_allocable, [here_label], [size]) + let loc = match loc with + | None -> Cil_datatype.Location.unknown + | Some l -> l + in + let is_allocable = get_is_allocable loc in + papp ~loc (is_allocable, [here_label], [size]) let is_allocable ?loc size = let p = pis_allocable ?loc size in @@ -60,10 +106,6 @@ let isnt_allocable ?loc size = let p = pnot ?loc (pis_allocable ?loc size) in new_predicate { p with pred_name = [ "allocable" ]} -let heap_status () = - let heap_status = Globals.Vars.find_from_astinfo "__fc_heap_status" VGlobal in - Basic_blocks.cvar_to_tvar (heap_status) - let assigns_result ?loc typ deps = let heap_status = new_identified_term (heap_status ()) in let deps = match deps with diff --git a/src/plugins/instantiate/stdlib/calloc.ml b/src/plugins/instantiate/stdlib/calloc.ml index 86eada6103dfa765956508a1e25c231a346199d9..cebc53197c970139cab11bfd44936719ff4518cb 100644 --- a/src/plugins/instantiate/stdlib/calloc.ml +++ b/src/plugins/instantiate/stdlib/calloc.ml @@ -34,7 +34,7 @@ let pset_len_to_zero ?loc alloc_type num size = let value = match Logic_utils.unroll_type t.term_type with | Ctype(TPtr(_)) -> term Tnull t.term_type | Ctype(TFloat(_)) -> treal ?loc 0. - | Ctype(TInt(_)) -> tinteger ?loc 0 + | Ctype(TInt(_) | TEnum (_)) -> tinteger ?loc 0 | _ -> unexpected "non atomic type during equality generation" in prel ?loc (Req, t, value) @@ -131,7 +131,7 @@ let generate_prototype alloc_type = ] in name, (TFun((ptr_of alloc_type), Some params, false, [])) -let well_typed_call ret args = +let well_typed_call ret _fct args = match ret, args with | Some ret, [ _ ; _ ] -> let t = Cil.typeOfLval ret in @@ -139,13 +139,13 @@ let well_typed_call ret args = Cil.isCompleteType (Cil.typeOf_pointed t) | _ -> false -let key_from_call ret _ = +let key_from_call ret _fct _ = match ret with | Some ret -> let ret_t = Cil.unrollTypeDeep (Cil.typeOfLval ret) in let ret_t = Cil.type_remove_qualifier_attributes_deep ret_t in Cil.typeOf_pointed ret_t - | None -> unexpected "trying to generate a key on an ill-typed call" + | _ -> unexpected "trying to generate a key on an ill-typed call" let retype_args _typ args = args let args_for_original _typ args = args diff --git a/src/plugins/instantiate/stdlib/free.ml b/src/plugins/instantiate/stdlib/free.ml index 7ef4c509bb20f13e505b79ab71a2feabc99d5436..b1adaae34a331f69f8b9f4110511a726cda44cb9 100644 --- a/src/plugins/instantiate/stdlib/free.ml +++ b/src/plugins/instantiate/stdlib/free.ml @@ -83,14 +83,14 @@ let generate_prototype alloc_t = ] in name, (TFun(Cil.voidType, Some params, false, [])) -let well_typed_call _ret args = +let well_typed_call _ret _fct args = match args with | [ ptr ] -> let t = Cil.typeOf (Cil.stripCasts ptr) in Cil.isPointerType t && not (Cil.isVoidPtrType t) | _ -> false -let key_from_call _ret args = +let key_from_call _ret _fct args = match args with | [ ptr ] -> let ptr = Cil.stripCasts ptr in diff --git a/src/plugins/instantiate/stdlib/malloc.ml b/src/plugins/instantiate/stdlib/malloc.ml index 16521b530aebe5561a445c1e30216d24b338feef..f7b3e9f3b0d3485f7cf7ace2a47d12712b19f0bd 100644 --- a/src/plugins/instantiate/stdlib/malloc.ml +++ b/src/plugins/instantiate/stdlib/malloc.ml @@ -70,7 +70,7 @@ let generate_prototype alloc_t = ] in name, (TFun((ptr_of alloc_t), Some params, false, [])) -let well_typed_call ret args = +let well_typed_call ret _fct args = match ret, args with | Some ret, [ _ ] -> let t = Cil.typeOfLval ret in @@ -78,13 +78,13 @@ let well_typed_call ret args = Cil.isCompleteType (Cil.typeOf_pointed t) | _ -> false -let key_from_call ret _ = +let key_from_call ret _fct _ = match ret with | Some ret -> let ret_t = Cil.unrollTypeDeep (Cil.typeOfLval ret) in let ret_t = Cil.type_remove_qualifier_attributes_deep ret_t in Cil.typeOf_pointed ret_t - | None -> unexpected "trying to generate a key on an ill-typed call" + | _ -> unexpected "trying to generate a key on an ill-typed call" let retype_args _typ args = args let args_for_original _typ args = args diff --git a/src/plugins/instantiate/string/mem_utils.ml b/src/plugins/instantiate/string/mem_utils.ml new file mode 100644 index 0000000000000000000000000000000000000000..de076b1e3c029f90e6ab4698b6ffe971b07c369b --- /dev/null +++ b/src/plugins/instantiate/string/mem_utils.ml @@ -0,0 +1,172 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2020 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +open Basic_blocks +open Cil_types +open Logic_const + +type kind = CPtr | Ptr | Data of typ +type action = Strip | Id +type param = string * kind * action +type proto = kind * param list +type 'a spec_gen = location -> typ -> term -> term -> term -> 'a + +type pointed_expr_type = + | Of_null of typ + | Value_of of typ + | No_pointed + +let exp_type_of_pointed x = + let no_cast = Cil.stripCasts x in + if not (Cil.isPointerType (Cil.typeOf no_cast)) then + match Cil.constFoldToInt x with + | Some t when Integer.(equal t (of_int 0)) -> + Of_null (Cil.typeOf_pointed (Cil.typeOf x)) + | _ -> + No_pointed + else + let xt = Cil.unrollTypeDeep (Cil.typeOf no_cast) in + let xt = Cil.type_remove_qualifier_attributes_deep xt in + Value_of (Cil.typeOf_pointed xt) + +let unexpected = Options.fatal "Mem_utils: %s" + +let mem2s_typing _ = function + | [ dest ; src ; len ] -> + (Cil.isIntegralType len) && + (Cil_datatype.Typ.equal dest src) && + (not (Cil.isVoidType dest)) && + (Cil.isCompleteType dest) + | _ -> false + +let mem2s_spec ~requires ~assigns ~ensures _t { svar = vi } loc = + let (cdest, csrc, clen) = match Cil.getFormalsDecl vi with + | [ dest ; src ; len ] -> dest, src, len + | _ -> unexpected "ill-formed fundec in specification generation" + in + let t = cdest.vtype in + let dest = cvar_to_tvar cdest in + let src = cvar_to_tvar csrc in + let len = cvar_to_tvar clen in + let requires = requires loc t dest src len in + let assigns = assigns loc t dest src len in + let ensures = ensures loc t dest src len in + make_funspec [make_behavior ~requires ~assigns ~ensures ()] () + +let pcopied_len_bytes ?loc p1 p2 bytes_len = + plet_len_div_size ?loc p1.term_type bytes_len + (punfold_all_elems_eq ?loc p1 p2) + +let memcpy_memmove_common_requires loc _ dest src len = + List.map new_predicate [ + { (pcorrect_len_bytes ~loc dest.term_type len) + with pred_name = ["aligned_end"] } ; + { (pvalid_len_bytes ~loc here_label dest len) + with pred_name = ["valid_dest"] } ; + { (pvalid_read_len_bytes ~loc here_label src len) + with pred_name = ["valid_read_src"] } ; + ] + +let memcpy_memmove_common_assigns loc t dest src len = + let dest_range = new_identified_term (tunref_range_bytes_len ~loc dest len) in + let src_range = new_identified_term(tunref_range_bytes_len ~loc src len) in + let copy = dest_range, From [src_range] in + let result = new_identified_term (tresult t) in + let dest = new_identified_term dest in + let res = result, From [dest] in + Writes [ copy ; res ] + +let presult_dest ?loc t dest = + prel ?loc (Req, (tresult ?loc t), dest) + +let memcpy_memmove_common_ensures name loc t dest src len = + List.map (fun p -> Normal, new_predicate p) [ + { (pcopied_len_bytes ~loc dest src len) with pred_name = [name] } ; + { (presult_dest ~loc t dest) with pred_name = ["result"] } + ] + +module type Function = sig + val name: string + val prototype: unit -> proto + val well_typed: typ option -> typ list -> bool +end + +module Make (F: Function) = +struct + let generate_function_type t = + let to_type = function + | CPtr -> ptr_of (const_of t) + | Ptr -> ptr_of t + | Data t -> t + in + let ret, ps = F.prototype () in + let ret = to_type ret in + let ps = List.map (fun (name, kind, _) -> name, (to_type kind), []) ps in + TFun(ret, Some ps, false, []) + + let generate_prototype t = + let ftype = generate_function_type t in + let name = F.name ^ "_" ^ (string_of_typ t) in + name, ftype + + let well_typed_call lval _fct args = + let _, ps = F.prototype () in + if List.length args <> List.length ps then false + else + let extract e = function + | _, (CPtr | Ptr), _ -> exp_type_of_pointed e + | _, Data _ , _ -> Value_of (Cil.typeOf e) + in + let lvt = Extlib.opt_map Cil.typeOfLval lval in + let pts = List.map2 extract args ps in + let is_no_pointed = function No_pointed -> true | _ -> false in + let the_typ = function + | No_pointed -> assert false + | Value_of t | Of_null t -> t + in + if List.exists is_no_pointed pts then false + else F.well_typed lvt (List.map the_typ pts) + + let retype_args _ args = + let _, ps = F.prototype () in + if List.length args <> List.length ps then + unexpected "trying to retype arguments on an ill-typed call" + else + let retype x = function + | _, _, Strip -> Cil.stripCasts x + | _, _, Id -> x + in + List.map2 retype args ps + + let key_from_call _ret _fct args = + let _, ps = F.prototype () in + match ps, args with + | (_, (Ptr|CPtr), _) :: ps, fst :: args + when List.(length ps = length args) -> + begin match exp_type_of_pointed fst with + | Value_of t -> t + | _ -> + unexpected "Mem_utils: trying to get key on an ill-typed call" + end + | _ -> + unexpected "Mem_utils: trying to get key on an ill-typed call" +end diff --git a/src/plugins/instantiate/string/mem_utils.mli b/src/plugins/instantiate/string/mem_utils.mli new file mode 100644 index 0000000000000000000000000000000000000000..2a580c48732ada81908001ff088e88858048da53 --- /dev/null +++ b/src/plugins/instantiate/string/mem_utils.mli @@ -0,0 +1,75 @@ +(**************************************************************************) +(* *) +(* This file is part of Frama-C. *) +(* *) +(* Copyright (C) 2007-2020 *) +(* CEA (Commissariat à l'énergie atomique et aux énergies *) +(* alternatives) *) +(* *) +(* you can redistribute it and/or modify it under the terms of the GNU *) +(* Lesser General Public License as published by the Free Software *) +(* Foundation, version 2.1. *) +(* *) +(* It is distributed in the hope that it will be useful, *) +(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) +(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) +(* GNU Lesser General Public License for more details. *) +(* *) +(* See the GNU Lesser General Public License version 2.1 *) +(* for more details (enclosed in the file licenses/LGPLv2.1). *) +(* *) +(**************************************************************************) + +open Cil_types + +type kind = CPtr | Ptr | Data of typ +type action = Strip | Id +type param = string * kind * action +type proto = kind * param list + +module type Function = sig + val name: string + + val prototype: unit -> proto + + (** receives the type of the lvalue and the types of the arguments received + for a call to the function and returns [true] iff they are correct. + The received types depend on the [prototype] of the module. + - if the kind is [Data t] -> it is the exact type of the expr/lvalue + - it the kind is [(C)Ptr] -> it is the pointed type of the expr/lvalue + *) + val well_typed: typ option -> typ list -> bool +end + +module Make (F: Function) : sig + val generate_function_type : typ -> typ + val generate_prototype : typ -> string * typ + val well_typed_call : lval option -> varinfo -> exp list -> bool + val retype_args : typ -> exp list -> exp list + val key_from_call : lval option -> varinfo -> exp list -> typ +end + +(** location -> key -> s1 -> s2 -> len -> spec_result *) +type 'a spec_gen = location -> typ -> term -> term -> term -> 'a + +val mem2s_spec: + requires: (identified_predicate list) spec_gen -> + assigns: assigns spec_gen -> + ensures: (termination_kind * identified_predicate) list spec_gen -> + typ -> fundec -> location -> funspec + +val mem2s_typing: typ option -> typ list -> bool + +val memcpy_memmove_common_requires: (identified_predicate list) spec_gen + +val memcpy_memmove_common_assigns: assigns spec_gen + +val memcpy_memmove_common_ensures: + string -> (termination_kind * identified_predicate) list spec_gen + +type pointed_expr_type = + | Of_null of typ + | Value_of of typ + | No_pointed + +val exp_type_of_pointed: exp -> pointed_expr_type diff --git a/src/plugins/instantiate/string/memcmp.ml b/src/plugins/instantiate/string/memcmp.ml index 633294db95b177f66c5f927cfc794f8e7dcc04c3..59969c7ddeed41df219bd4ab7f2bd52d29d2e00c 100644 --- a/src/plugins/instantiate/string/memcmp.ml +++ b/src/plugins/instantiate/string/memcmp.ml @@ -26,9 +26,7 @@ open Basic_blocks let function_name = "memcmp" -let unexpected = Options.fatal "String.Memcmp: unexpected: %s" - -let generate_requires loc s1 s2 len = +let requires loc _ s1 s2 len = List.map new_predicate [ { (pcorrect_len_bytes ~loc s1.term_type len) with pred_name = ["aligned_end"] } ; @@ -43,7 +41,7 @@ let presult_memcmp ?loc p1 p2 len = let res = prel ?loc (Req, (tresult ?loc Cil.intType), (tinteger ?loc 0)) in piff ?loc (res, eq) -let generate_assigns loc s1 s2 len = +let assigns loc _ s1 s2 len = let indirect_range loc s len = new_identified_term { (tunref_range_bytes_len ~loc s len) with term_name = ["indirect"] } @@ -57,78 +55,37 @@ let generate_assigns loc s1 s2 len = let presult_memcmp_len_bytes ?loc p1 p2 bytes_len = plet_len_div_size ?loc p1.term_type bytes_len (presult_memcmp ?loc p1 p2) -let generate_ensures loc s1 s2 len = +let ensures loc _ s1 s2 len = List.map (fun p -> Normal, new_predicate p) [ { (presult_memcmp_len_bytes ~loc s1 s2 len) with pred_name = [ "equals" ] } ] -let generate_spec _t { svar = vi } loc = - let (c_s1, c_s2, clen) = match Cil.getFormalsDecl vi with - | [ s1 ; s2 ; len ] -> s1, s2, len - | _ -> unexpected "ill-formed fundec in specification generation" - in - let s1 = cvar_to_tvar c_s1 in - let s2 = cvar_to_tvar c_s2 in - let len = cvar_to_tvar clen in - let requires = generate_requires loc s1 s2 len in - let assigns = generate_assigns loc s1 s2 len in - let ensures = generate_ensures loc s1 s2 len in - make_funspec [make_behavior ~requires ~assigns ~ensures ()] () - -let generate_function_type t = - let t = ptr_of (const_of t) in - let params = [ - ("s1", t, []) ; - ("s2", t, []) ; - ("len", size_t (), []) - ] in - TFun(Cil.intType, Some params, false, []) - -let generate_prototype t = - let fun_type = generate_function_type t in - let name = function_name ^ "_" ^ (string_of_typ t) in - name, fun_type - -let type_from_arg x = - let x = Cil.stripCasts x in - let xt = Cil.unrollTypeDeep (Cil.typeOf x) in - let xt = Cil.type_remove_qualifier_attributes_deep xt in - Cil.typeOf_pointed xt - -let well_typed_call _ret = function - | [ s1 ; s2 ; len ] -> - (Cil.isIntegralType (Cil.typeOf len)) && - (Cil_datatype.Typ.equal (type_from_arg s1) (type_from_arg s2)) && - (not (Cil.isVoidType (type_from_arg s1))) && - (Cil.isCompleteType (type_from_arg s1)) - | _ -> false - -let key_from_call _ret = function - | [ s1 ; _ ; _ ] -> type_from_arg s1 - | _ -> unexpected "trying to generate a key on an ill-typed call" - -let retype_args override_key = function - | [ s1 ; s2 ; len ] -> - let s1 = Cil.stripCasts s1 in - let s2 = Cil.stripCasts s2 in - assert ( - Cil_datatype.Typ.equal (type_from_arg s1) override_key && - Cil_datatype.Typ.equal (type_from_arg s2) override_key - ) ; - [ s1 ; s2 ; len ] - | _ -> unexpected "trying to retype arguments on an ill-typed call" - -let args_for_original _t args = args +let generate_spec = Mem_utils.mem2s_spec ~requires ~assigns ~ensures + +module Function = +struct + open Mem_utils + let name = function_name + let prototype () = + Data Cil.intType, + [ + ("s1" , CPtr,Strip) ; + ("s2" , CPtr,Strip) ; + ("len", Data (size_t ()) ,Id) + ] + let well_typed = Mem_utils.mem2s_typing +end +module Memcmp_base = Mem_utils.Make(Function) let () = Transform.register (module struct module Hashtbl = Cil_datatype.Typ.Hashtbl type override_key = typ let function_name = function_name - let well_typed_call = well_typed_call - let key_from_call = key_from_call - let retype_args = retype_args - let generate_prototype = generate_prototype + let well_typed_call = Memcmp_base.well_typed_call + let key_from_call = Memcmp_base.key_from_call + let retype_args = Memcmp_base.retype_args + let generate_prototype = Memcmp_base.generate_prototype let generate_spec = generate_spec - let args_for_original = args_for_original + let args_for_original _ = Extlib.id end) diff --git a/src/plugins/instantiate/string/memcpy.ml b/src/plugins/instantiate/string/memcpy.ml index d0db608eef172febd0665fb56a38d9543131e16a..e56778e6a5714e879f090c0421c121d5ea61dcb6 100644 --- a/src/plugins/instantiate/string/memcpy.ml +++ b/src/plugins/instantiate/string/memcpy.ml @@ -23,118 +23,48 @@ open Cil_types open Logic_const open Basic_blocks +open Mem_utils let function_name = "memcpy" -let unexpected = Options.fatal "String.Memcpy: unexpected: %s" - let pseparated_memcpy_len_bytes ?loc p1 p2 bytes_len = let generate len = pseparated_memories ?loc p1 len p2 len in plet_len_div_size ?loc p1.term_type bytes_len generate -let pcopied_len_bytes ?loc p1 p2 bytes_len = - plet_len_div_size ?loc p1.term_type bytes_len - (punfold_all_elems_eq ?loc p1 p2) - -let presult_dest ?loc t dest = - prel ?loc (Req, (tresult ?loc t), dest) - -let generate_requires loc dest src len = - List.map new_predicate [ - { (pcorrect_len_bytes ~loc dest.term_type len) - with pred_name = ["aligned_end"] } ; - { (pvalid_len_bytes ~loc here_label dest len) - with pred_name = ["valid_dest"] } ; - { (pvalid_read_len_bytes ~loc here_label src len) - with pred_name = ["valid_read_src"] } ; - { (pseparated_memcpy_len_bytes ~loc dest src len) - with pred_name = ["separation"] } - ] - -let generate_assigns loc t dest src len = - let dest_range = new_identified_term (tunref_range_bytes_len ~loc dest len) in - let src_range = new_identified_term(tunref_range_bytes_len ~loc src len) in - let copy = dest_range, From [src_range] in - let result = new_identified_term (tresult t) in - let dest = new_identified_term dest in - let res = result, From [dest] in - Writes [ copy ; res ] - -let generate_ensures loc t dest src len = - List.map (fun p -> Normal, new_predicate p) [ - { (pcopied_len_bytes ~loc dest src len) with pred_name = [ "copied"] } ; - { (presult_dest ~loc t dest) with pred_name = [ "result"] } - ] - -let generate_spec _t { svar = vi } loc = - let (cdest, csrc, clen) = match Cil.getFormalsDecl vi with - | [ dest ; src ; len ] -> dest, src, len - | _ -> unexpected "ill-formed fundec in specification generation" +let requires loc t dest src len = + let separated = new_predicate + { (pseparated_memcpy_len_bytes ~loc dest src len) + with pred_name = ["separation"] } in - let t = cdest.vtype in - let dest = cvar_to_tvar cdest in - let src = cvar_to_tvar csrc in - let len = cvar_to_tvar clen in - let requires = generate_requires loc dest src len in - let assigns = generate_assigns loc t dest src len in - let ensures = generate_ensures loc t dest src len in - make_funspec [make_behavior ~requires ~assigns ~ensures ()] () - -let generate_function_type t = - let dt = ptr_of t in - let st = ptr_of (const_of t) in - let params = [ - ("dest", dt, []) ; - ("src", st, []) ; - ("len", size_t (), []) - ] in - TFun(dt, Some params, false, []) - -let generate_prototype t = - let fun_type = generate_function_type t in - let name = function_name ^ "_" ^ (string_of_typ t) in - name, fun_type - -let type_from_arg x = - let x = Cil.stripCasts x in - let xt = Cil.unrollTypeDeep (Cil.typeOf x) in - let xt = Cil.type_remove_qualifier_attributes_deep xt in - Cil.typeOf_pointed xt - -let well_typed_call _ret = function - | [ dest ; src ; len ] -> - (Cil.isIntegralType (Cil.typeOf len)) && - (Cil_datatype.Typ.equal (type_from_arg dest) (type_from_arg src)) && - (not (Cil.isVoidType (type_from_arg dest))) && - (Cil.isCompleteType (type_from_arg dest)) - | _ -> false - -let key_from_call _ret = function - | [ dest ; _ ; _ ] -> type_from_arg dest - | _ -> unexpected "trying to generate a key on an ill-typed call" - -let retype_args override_key = function - | [ dest ; src ; len ] -> - let dest = Cil.stripCasts dest in - let src = Cil.stripCasts src in - assert ( - Cil_datatype.Typ.equal (type_from_arg dest) override_key && - Cil_datatype.Typ.equal (type_from_arg src) override_key - ) ; - [ dest ; src ; len ] - | _ -> unexpected "trying to retype arguments on an ill-typed call" - -let args_for_original _t args = args + separated :: (memcpy_memmove_common_requires loc t dest src len) + +let assigns = memcpy_memmove_common_assigns +let ensures = memcpy_memmove_common_ensures "copied" +let generate_spec = mem2s_spec ~requires ~assigns ~ensures + +module Function = +struct + let name = function_name + let prototype () = + Ptr, + [ + ("dest", Ptr, Strip) ; + ("src", CPtr, Strip) ; + ("len", Data (size_t()), Id) + ] + let well_typed = Mem_utils.mem2s_typing +end +module Memcpy_base = Mem_utils.Make(Function) let () = Transform.register (module struct module Hashtbl = Cil_datatype.Typ.Hashtbl type override_key = typ let function_name = function_name - let well_typed_call = well_typed_call - let key_from_call = key_from_call - let retype_args = retype_args - let generate_prototype = generate_prototype + let well_typed_call = Memcpy_base.well_typed_call + let key_from_call = Memcpy_base.key_from_call + let retype_args = Memcpy_base.retype_args + let generate_prototype = Memcpy_base.generate_prototype let generate_spec = generate_spec - let args_for_original = args_for_original + let args_for_original _ = Extlib.id end) diff --git a/src/plugins/instantiate/string/memmove.ml b/src/plugins/instantiate/string/memmove.ml index 6481c423a1ff763ac83f433f801d5872b1d75876..9ce6d75b6bdd8db4598ad0208d393a6cb6ae3059 100644 --- a/src/plugins/instantiate/string/memmove.ml +++ b/src/plugins/instantiate/string/memmove.ml @@ -21,114 +21,38 @@ (**************************************************************************) open Cil_types -open Logic_const -open Basic_blocks +open Mem_utils let function_name = "memmove" -let unexpected = Options.fatal "String.Memmove: unexpected: %s" - -let pmoved_len_bytes ?loc dest src bytes_len = - plet_len_div_size ?loc dest.term_type bytes_len - (punfold_all_elems_eq ?loc dest src) - -let presult_dest ?loc t dest = - prel ?loc (Req, (tresult ?loc t), dest) - -let generate_requires loc dest src len = - List.map new_predicate [ - { (pcorrect_len_bytes ~loc dest.term_type len) - with pred_name = ["aligned_end"] } ; - { (pvalid_len_bytes ~loc here_label dest len) - with pred_name = ["valid_dest"] } ; - { (pvalid_read_len_bytes ~loc here_label src len) - with pred_name = ["valid_read_src"] } ; - ] - -let generate_assigns loc t dest src len = - let dest_range = new_identified_term (tunref_range_bytes_len ~loc dest len) in - let src_range = new_identified_term(tunref_range_bytes_len ~loc src len) in - let copy = dest_range, From [src_range] in - let result = new_identified_term (tresult t) in - let dest = new_identified_term dest in - let res = result, From [dest] in - Writes [ copy ; res ] - -let generate_ensures loc t dest src len = - List.map (fun p -> Normal, new_predicate p) [ - { (pmoved_len_bytes ~loc dest src len) with pred_name = [ "moved"] } ; - { (presult_dest ~loc t dest) with pred_name = [ "result"] } - ] - -let generate_spec _t { svar = vi } loc = - let (cdest, csrc, clen) = match Cil.getFormalsDecl vi with - | [ dest ; src ; len ] -> dest, src, len - | _ -> unexpected "ill-formed fundec in specification generation" - in - let t = cdest.vtype in - let dest = cvar_to_tvar cdest in - let src = cvar_to_tvar csrc in - let len = cvar_to_tvar clen in - let requires = generate_requires loc dest src len in - let assigns = generate_assigns loc t dest src len in - let ensures = generate_ensures loc t dest src len in - make_funspec [make_behavior ~requires ~assigns ~ensures ()] () - -let generate_function_type t = - let dt = ptr_of t in - let st = ptr_of (const_of t) in - let params = [ - ("dest", dt, []) ; - ("src", st, []) ; - ("len", size_t (), []) - ] in - TFun(dt, Some params, false, []) - -let generate_prototype t = - let fun_type = generate_function_type t in - let name = function_name ^ "_" ^ (string_of_typ t) in - name, fun_type - -let type_from_arg x = - let x = Cil.stripCasts x in - let xt = Cil.unrollTypeDeep (Cil.typeOf x) in - let xt = Cil.type_remove_qualifier_attributes_deep xt in - Cil.typeOf_pointed xt - -let well_typed_call _ret = function - | [ dest ; src ; len ] -> - (Cil.isIntegralType (Cil.typeOf len)) && - (Cil_datatype.Typ.equal (type_from_arg dest) (type_from_arg src)) && - (not (Cil.isVoidType (type_from_arg dest))) && - (Cil.isCompleteType (type_from_arg dest)) - | _ -> false - -let key_from_call _ret = function - | [ dest ; _ ; _ ] -> type_from_arg dest - | _ -> unexpected "trying to generate a key on an ill-typed call" - -let retype_args override_key = function - | [ dest ; src ; len ] -> - let dest = Cil.stripCasts dest in - let src = Cil.stripCasts src in - assert ( - Cil_datatype.Typ.equal (type_from_arg dest) override_key && - Cil_datatype.Typ.equal (type_from_arg src) override_key - ) ; - [ dest ; src ; len ] - | _ -> unexpected "trying to retype arguments on an ill-typed call" - -let args_for_original _t args = args +let requires = memcpy_memmove_common_requires +let assigns = memcpy_memmove_common_assigns +let ensures = memcpy_memmove_common_ensures "moved" +let generate_spec = mem2s_spec ~requires ~assigns ~ensures + +module Function = +struct + let name = function_name + let prototype () = + Ptr, + [ + ("dest", Ptr, Strip); + ("src" , CPtr, Strip); + ("len", Data (Basic_blocks.size_t()), Id) + ] + let well_typed = Mem_utils.mem2s_typing +end +module Memmove_base = Mem_utils.Make(Function) let () = Transform.register (module struct module Hashtbl = Cil_datatype.Typ.Hashtbl type override_key = typ let function_name = function_name - let well_typed_call = well_typed_call - let key_from_call = key_from_call - let retype_args = retype_args - let generate_prototype = generate_prototype + let well_typed_call = Memmove_base.well_typed_call + let key_from_call = Memmove_base.key_from_call + let retype_args = Memmove_base.retype_args + let generate_prototype = Memmove_base.generate_prototype let generate_spec = generate_spec - let args_for_original = args_for_original + let args_for_original _ = Extlib.id end) diff --git a/src/plugins/instantiate/string/memset.ml b/src/plugins/instantiate/string/memset.ml index 393f6ae626bc5595188e3a252395c8e845b391c6..1538ba32be03820bce1499f1dc1d25cdc35be6ff 100644 --- a/src/plugins/instantiate/string/memset.ml +++ b/src/plugins/instantiate/string/memset.ml @@ -68,7 +68,7 @@ let pset_len_bytes_to_zero ?loc ptr bytes_len = let value = match Logic_utils.unroll_type t.term_type with | Ctype(TPtr(_)) -> term Tnull t.term_type | Ctype(TFloat(_)) -> treal ?loc 0. - | Ctype(TInt(_)) -> tinteger ?loc 0 + | Ctype(TInt(_) | TEnum (_)) -> tinteger ?loc 0 | _ -> unexpected "non atomic type during equality generation" in prel ?loc (Req, t, value) @@ -89,15 +89,18 @@ let pset_len_bytes_all_bits_to_one ?loc ptr bytes_len = papp ?loc ((find_nan_for_type t.term_type), [], [t]) | Ctype(TPtr(_)) -> pnot ?loc (pvalid_read ?loc (here_label, t)) - | Ctype(TInt(kind, _)) | Ctype(TEnum({ ekind = kind }, _)) -> + | Ctype((TInt(kind, _) | TEnum({ ekind = kind }, _)) as typ) -> let is_signed = Cil.isSigned kind in let bits = Cil.bitsSizeOfInt kind in - let value = if is_signed then - Cil.min_signed_number bits + let value = + if is_signed then + let zero = tinteger ?loc 0 in + let zero = Logic_utils.mk_cast ?loc typ zero in + term (TUnOp(BNot, zero)) t.term_type else - Cil.max_unsigned_number bits + let value = Cil.max_unsigned_number bits in + term ?loc (TConst (Integer (value,None))) Linteger in - let value = term ?loc (TConst (Integer (value,None))) Linteger in prel ?loc (Req, t, value) | _ -> unexpected "non atomic type during equality generation" @@ -175,12 +178,6 @@ let generate_spec (_t, e) { svar = vi } loc = let ensures = generate_ensures e loc t ptr value len in make_funspec [make_behavior ~requires ~assigns ~ensures ()] () -let type_from_arg x = - let x = Cil.stripCasts x in - let xt = Cil.unrollTypeDeep (Cil.typeOf x) in - let xt = Cil.type_remove_qualifier_attributes_deep xt in - Cil.typeOf_pointed xt - let memset_value e = let ff = Integer.of_int 255 in match (Cil.constFold false e).enode with @@ -198,23 +195,26 @@ let rec contains_union_type t = contains_union_type t | _ -> false -let well_typed_call _ret = function - | [ ptr ; _ ; _ ] when any_char_composed_type (type_from_arg ptr) -> true - | [ ptr ; _ ; _ ] when contains_union_type (type_from_arg ptr) -> false - | [ ptr ; _ ; _ ] when Cil.isVoidType (type_from_arg ptr) -> false - | [ ptr ; _ ; _ ] when not (Cil.isCompleteType (type_from_arg ptr)) -> false - | [ _ ; value ; _ ] -> - begin match memset_value value with - | None -> false - | Some _ -> true +let well_typed_call _ret _fct = function + | [ ptr ; value ; _ ] -> + begin match Mem_utils.exp_type_of_pointed ptr, memset_value value with + | (No_pointed | Of_null _) , _ -> false + | Value_of t , _ when any_char_composed_type t -> true + | Value_of t , _ when contains_union_type t -> false + | Value_of t , _ when Cil.isVoidType t -> false + | Value_of t , _ when not (Cil.isCompleteType t) -> false + | _, None -> false + | _, Some _ -> true end | _ -> false -let key_from_call _ret = function - | [ ptr ; _ ; _ ] when any_char_composed_type (type_from_arg ptr) -> - (type_from_arg ptr), None - | [ ptr ; value ; _ ] when not (contains_union_type (type_from_arg ptr)) -> - (type_from_arg ptr), (memset_value value) +let key_from_call _ret _fct = function + | [ ptr ; value ; _ ] -> + begin match Mem_utils.exp_type_of_pointed ptr, memset_value value with + | Value_of t, _ when any_char_composed_type t -> t, None + | Value_of t, value when not (contains_union_type t) -> t, value + | _ , _ -> unexpected "trying to generate a key on an ill-typed call" + end | _ -> unexpected "trying to generate a key on an ill-typed call" let char_prototype t = @@ -246,17 +246,18 @@ let generate_prototype = function | _, _ -> unexpected "trying to generate a prototype on an ill-typed call" -let retype_args (t, e) args = +let retype_args (_t, e) args = match e, args with | None, [ ptr ; v ; n ] -> let ptr = Cil.stripCasts ptr in - assert (any_char_composed_type (type_from_arg ptr)) ; - let base_type = base_char_type (type_from_arg ptr) in + let base_type = match Mem_utils.exp_type_of_pointed ptr with + | Value_of t -> base_char_type t + | _ -> unexpected "trying to retype arguments on an ill-typed call" + in let v = Cil.mkCast (Cil.stripCasts v) base_type in [ ptr ; v ; n ] | Some fv, [ ptr ; v ; n ] -> let ptr = Cil.stripCasts ptr in - assert (Cil_datatype.Typ.equal (type_from_arg ptr) t) ; assert (match memset_value v with Some x when x = fv -> true | _ -> false) ; [ ptr ; n ] | _ -> diff --git a/src/plugins/instantiate/tests/api/external_instantiator_registration.ml b/src/plugins/instantiate/tests/api/external_instantiator_registration.ml index b800bd1efbdd4bd92fe985fab4771f1f001c95cd..aa3c9b5c6a425206aeae937f7d69d88e2f9db39c 100644 --- a/src/plugins/instantiate/tests/api/external_instantiator_registration.ml +++ b/src/plugins/instantiate/tests/api/external_instantiator_registration.ml @@ -1,12 +1,12 @@ let function_name = "mine" -let well_typed_call _ = function +let well_typed_call _ _ = function | [ e ] -> let t = Cil.typeOf(Cil.stripCasts e) in not (Cil.isVoidPtrType t) && Cil.isPointerType t | _ -> false -let key_from_call _ = function +let key_from_call _ _ = function | [ e ] -> let t = Cil.typeOf(Cil.stripCasts e) in Cil.typeOf_pointed t diff --git a/src/plugins/instantiate/tests/options/oracle/ignore-functions.res.oracle b/src/plugins/instantiate/tests/options/oracle/ignore-functions.res.oracle index 8aacf1fa7571bddc9c3fb5e630e1213db9a447bd..b260fc61afd6d08b2f133412781ca83183fc8f50 100644 --- a/src/plugins/instantiate/tests/options/oracle/ignore-functions.res.oracle +++ b/src/plugins/instantiate/tests/options/oracle/ignore-functions.res.oracle @@ -11,16 +11,16 @@ void foo(void) return; } -/*@ requires aligned_end: len % 4 ≡ 0; +/*@ requires + separation: + \let __fc_len = len / 4; + \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); + requires aligned_end: len % 4 ≡ 0; requires valid_dest: \let __fc_len = len / 4; \valid(dest + (0 .. __fc_len - 1)); requires valid_read_src: \let __fc_len = len / 4; \valid_read(src + (0 .. __fc_len - 1)); - requires - separation: - \let __fc_len = len / 4; - \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); ensures copied: \let __fc_len = len / 4; diff --git a/src/plugins/instantiate/tests/options/oracle/only-functions.res.oracle b/src/plugins/instantiate/tests/options/oracle/only-functions.res.oracle index cc08c601aac8ee1d7015befe833d0946ebe43eb9..d84cec92ebc1968177fac95b8d64c5fa172c3976 100644 --- a/src/plugins/instantiate/tests/options/oracle/only-functions.res.oracle +++ b/src/plugins/instantiate/tests/options/oracle/only-functions.res.oracle @@ -3,16 +3,16 @@ #include "stddef.h" #include "string.h" #include "strings.h" -/*@ requires aligned_end: len % 4 ≡ 0; +/*@ requires + separation: + \let __fc_len = len / 4; + \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); + requires aligned_end: len % 4 ≡ 0; requires valid_dest: \let __fc_len = len / 4; \valid(dest + (0 .. __fc_len - 1)); requires valid_read_src: \let __fc_len = len / 4; \valid_read(src + (0 .. __fc_len - 1)); - requires - separation: - \let __fc_len = len / 4; - \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); ensures copied: \let __fc_len = len / 4; diff --git a/src/plugins/instantiate/tests/plugin/ast_clear.c b/src/plugins/instantiate/tests/plugin/ast_clear.c new file mode 100644 index 0000000000000000000000000000000000000000..d3dfbb6ad2a2fb83924f23cba30589f680d415e9 --- /dev/null +++ b/src/plugins/instantiate/tests/plugin/ast_clear.c @@ -0,0 +1,9 @@ +/* run.config + OPT: -instantiate -then -pp-annot +*/ + +#include <string.h> + +int foo(char* s1, char* s2, size_t len){ + return memcmp(s1, s2, len) ; +} \ No newline at end of file diff --git a/src/plugins/instantiate/tests/plugin/needs_global.i b/src/plugins/instantiate/tests/plugin/needs_global.i new file mode 100644 index 0000000000000000000000000000000000000000..dfd53797477e08a50c44b80b06ea9743a7a73614 --- /dev/null +++ b/src/plugins/instantiate/tests/plugin/needs_global.i @@ -0,0 +1,14 @@ +/* run.config + OPT: -load-script tests/plugin/needs_globals.ml -instantiate -check -print +*/ + +int i ; // needed for already_one specifciation +void already_one(void* parameter) ; + +void needs_new(void* parameter) ; + +void foo(void){ + int *i ; + already_one(i); + needs_new(i); +} diff --git a/src/plugins/instantiate/tests/plugin/needs_globals.ml b/src/plugins/instantiate/tests/plugin/needs_globals.ml new file mode 100644 index 0000000000000000000000000000000000000000..506da455fdb5b23a60a0d994dc2fcfb0e268c021 --- /dev/null +++ b/src/plugins/instantiate/tests/plugin/needs_globals.ml @@ -0,0 +1,80 @@ +let well_typed_call _ _ = function + | [ e ] -> + let t = Cil.typeOf(Cil.stripCasts e) in + not (Cil.isVoidPtrType t) && Cil.isPointerType t + | _ -> false + +let key_from_call _ _ = function + | [ e ] -> Cil.typeOf_pointed (Cil.typeOf(Cil.stripCasts e)) + | _ -> assert false + +let retype_args _ = function + | [ e ] -> [ Cil.stripCasts e ] + | _ -> assert false + +let generate_function_type t = + let params = [("x", Cil_types.TPtr(t, []), [])] in + Cil_types.TFun(Cil.voidType, Some params, false, []) + +let generate_prototype function_name t = + let fun_type = generate_function_type t in + let name = function_name ^ "_" ^ match t with + | Cil_types.TInt(_) -> "int" + | _ -> assert false (* nothing else in our test *) + in + name, fun_type + +let generate_spec needed _ _ _ = + let open Cil_types in + let open Logic_const in + let open Instantiate.Global_context in + let make () = + let vi = Cil.makeVarinfo ~ghost:true true false needed Cil.floatType in + vi.vstorage <- Extern ; + vi + in + let vi = get_variable needed make in + let t = tvar (Cil.cvar_to_lvar vi) in + let assigns = + Cil_types.Writes [ Logic_const.new_identified_term t, From [] ] + in { + spec_behavior = [ { + b_name = Cil.default_behavior_name ; + b_requires = [] ; + b_assumes = [] ; + b_post_cond = [] ; + b_assigns = assigns ; + b_allocation = FreeAllocAny ; + b_extended = [] + } ] ; + spec_variant = None ; + spec_terminates = None ; + spec_complete_behaviors = [] ; + spec_disjoint_behaviors = [] ; + } + +let () = Instantiate.Transform.register (module struct + module Hashtbl = Cil_datatype.Typ.Hashtbl + type override_key = Hashtbl.key + + let function_name = "already_one" + let well_typed_call = well_typed_call + let key_from_call = key_from_call + let retype_args = retype_args + let generate_prototype = generate_prototype function_name + let generate_spec = generate_spec "i" + let args_for_original _ = Extlib.id + end) + +let () = Instantiate.Transform.register (module struct + module Hashtbl = Cil_datatype.Typ.Hashtbl + type override_key = Hashtbl.key + + let function_name = "needs_new" + let well_typed_call = well_typed_call + let key_from_call = key_from_call + let retype_args = retype_args + let generate_prototype = generate_prototype function_name + let generate_spec = generate_spec "j" + let args_for_original _ = Extlib.id + end) diff --git a/src/plugins/instantiate/tests/plugin/oracle/ast_clear.res.oracle b/src/plugins/instantiate/tests/plugin/oracle/ast_clear.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..1a8c67bb4f4a92cf3d5a5f39514eb119d0d7c121 --- /dev/null +++ b/src/plugins/instantiate/tests/plugin/oracle/ast_clear.res.oracle @@ -0,0 +1,2 @@ +[kernel] Parsing tests/plugin/ast_clear.c (with preprocessing) +[kernel] Parsing tests/plugin/ast_clear.c (with preprocessing) diff --git a/src/plugins/instantiate/tests/plugin/oracle/needs_global.res.oracle b/src/plugins/instantiate/tests/plugin/oracle/needs_global.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..0b7e5b4ccb788b009ffd587ae9e1b13389cd66d0 --- /dev/null +++ b/src/plugins/instantiate/tests/plugin/oracle/needs_global.res.oracle @@ -0,0 +1,34 @@ +[kernel] Parsing tests/plugin/needs_global.i (no preprocessing) +/* Generated by Frama-C */ +/*@ ghost extern float j; */ + +int i; +void already_one(void *parameter); + +void needs_new(void *parameter); + +/*@ assigns j; + assigns j \from \nothing; */ +void needs_new_int(int *x) +{ + needs_new((void *)x); + return; +} + +/*@ assigns i; + assigns i \from \nothing; */ +void already_one_int(int *x) +{ + already_one((void *)x); + return; +} + +void foo(void) +{ + int *i_0; + already_one_int(i_0); + needs_new_int(i_0); + return; +} + + diff --git a/src/plugins/instantiate/tests/stdlib/calloc.c b/src/plugins/instantiate/tests/stdlib/calloc.c index 87b1f9338ccb5ecdd99d339551a383459f8305bc..d87508ad415bcf21b677949b5429c8b8b376fc97 100644 --- a/src/plugins/instantiate/tests/stdlib/calloc.c +++ b/src/plugins/instantiate/tests/stdlib/calloc.c @@ -11,8 +11,11 @@ struct Flex { int f[] ; } ; +enum E { A, B, C }; + int main(void){ int* pi = calloc(10, sizeof(int)) ; + enum E* pe = calloc(10, sizeof(enum E)) ; float* pf = calloc(10, sizeof(float)) ; struct X* px = calloc(10, sizeof(struct X)) ; char* pc = calloc(10, sizeof(char)) ; diff --git a/src/plugins/instantiate/tests/stdlib/no_fc_stdlib.c b/src/plugins/instantiate/tests/stdlib/no_fc_stdlib.c new file mode 100644 index 0000000000000000000000000000000000000000..21498c2ef2b5ab29516316267bc33c5af6d46bbd --- /dev/null +++ b/src/plugins/instantiate/tests/stdlib/no_fc_stdlib.c @@ -0,0 +1,12 @@ +#include <stddef.h> + +void* malloc(size_t s); +void* calloc(size_t num, size_t size); +void free(void* ptr); + +void foo(void){ + int * p = malloc(sizeof(int)); + int * q = calloc(2, sizeof(int)); + free(p); + free(q); +} \ No newline at end of file diff --git a/src/plugins/instantiate/tests/stdlib/oracle/calloc.res.oracle b/src/plugins/instantiate/tests/stdlib/oracle/calloc.res.oracle index 28d42c036e394314e15f148be188d770b46886e9..1670641826813ce9b10d06d60f85849cf9e55a57 100644 --- a/src/plugins/instantiate/tests/stdlib/oracle/calloc.res.oracle +++ b/src/plugins/instantiate/tests/stdlib/oracle/calloc.res.oracle @@ -1,6 +1,8 @@ [kernel] Parsing tests/stdlib/calloc.c (with preprocessing) -[instantiate] tests/stdlib/calloc.c:21: Warning: Ignore call: not well typed -[instantiate] tests/stdlib/calloc.c:22: Warning: Ignore call: not well typed +[instantiate] tests/stdlib/calloc.c:24: Warning: + calloc instantiator cannot replace call +[instantiate] tests/stdlib/calloc.c:25: Warning: + calloc instantiator cannot replace call /* Generated by Frama-C */ #include "stdlib.h" struct X { @@ -12,6 +14,11 @@ struct Flex { char c ; int f[] ; }; +enum E { + A = 0, + B = 1, + C = 2 +}; struct incomplete; /*@ requires correct_size: 0 ≤ size - 8 ∧ 0 ≡ (size - 8) % 4; requires only_one: num ≡ 1; @@ -216,6 +223,43 @@ float *calloc_float(size_t num, size_t size) return __retres; } +/*@ requires correct_size: 0 ≡ size % 4; + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, num, size; + assigns __fc_heap_status \from __fc_heap_status, num, size; + allocates \result; + + behavior allocation: + assumes allocable: is_allocable(num * size); + ensures fresh_result: \fresh{Old, Here}(\result,num * size); + ensures + zero_initialization: + ∀ ℤ j0; 0 ≤ j0 < num ⇒ *(\result + j0) ≡ 0; + ensures + initialization: + ∀ ℤ j0; 0 ≤ j0 < num ⇒ \initialized(\result + j0); + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, num, size; + assigns __fc_heap_status \from __fc_heap_status, num, size; + allocates \result; + + behavior no_allocation: + assumes allocable: ¬is_allocable(num * size); + ensures null_result: \result ≡ \null; + assigns \result; + assigns \result \from \nothing; + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +enum E *calloc_e_E(size_t num, size_t size) +{ + enum E *__retres; + __retres = (enum E *)calloc(num,size); + return __retres; +} + /*@ requires correct_size: 0 ≡ size % 4; assigns \result, __fc_heap_status; assigns \result \from __fc_heap_status, num, size; @@ -257,6 +301,7 @@ int main(void) { int __retres; int *pi = calloc_int((unsigned int)10,sizeof(int)); + enum E *pe = calloc_e_E((unsigned int)10,sizeof(enum E)); float *pf = calloc_float((unsigned int)10,sizeof(float)); struct X *px = calloc_st_X((unsigned int)10,sizeof(struct X)); char *pc = calloc_char((unsigned int)10,sizeof(char)); @@ -283,6 +328,11 @@ struct Flex { char c ; int f[] ; }; +enum E { + A = 0, + B = 1, + C = 2 +}; struct incomplete; /*@ requires correct_size: 0 ≤ size - 8 ∧ 0 ≡ (size - 8) % 4; requires only_one: num ≡ 1; @@ -490,6 +540,44 @@ float *calloc_float(size_t num, size_t size) return __retres; } +/*@ requires correct_size: 0 ≡ size % 4; + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, num, size; + assigns __fc_heap_status \from __fc_heap_status, num, size; + allocates \result; + + behavior allocation: + assumes allocable: is_allocable(num * size); + ensures + fresh_result: \fresh{Old, Here}(\result,\old(num) * \old(size)); + ensures + zero_initialization: + ∀ ℤ j0; 0 ≤ j0 < \old(num) ⇒ *(\result + j0) ≡ 0; + ensures + initialization: + ∀ ℤ j0; 0 ≤ j0 < \old(num) ⇒ \initialized(\result + j0); + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, num, size; + assigns __fc_heap_status \from __fc_heap_status, num, size; + allocates \result; + + behavior no_allocation: + assumes allocable: ¬is_allocable(num * size); + ensures null_result: \result ≡ \null; + assigns \result; + assigns \result \from \nothing; + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +enum E *calloc_e_E(size_t num, size_t size) +{ + enum E *__retres; + __retres = (enum E *)calloc(num,size); + return __retres; +} + /*@ requires correct_size: 0 ≡ size % 4; assigns \result, __fc_heap_status; assigns \result \from __fc_heap_status, num, size; @@ -532,6 +620,7 @@ int main(void) { int __retres; int *pi = calloc_int((unsigned int)10,sizeof(int)); + enum E *pe = calloc_e_E((unsigned int)10,sizeof(enum E)); float *pf = calloc_float((unsigned int)10,sizeof(float)); struct X *px = calloc_st_X((unsigned int)10,sizeof(struct X)); char *pc = calloc_char((unsigned int)10,sizeof(char)); diff --git a/src/plugins/instantiate/tests/stdlib/oracle/free.res.oracle b/src/plugins/instantiate/tests/stdlib/oracle/free.res.oracle index cfdb769ed8d5e5412d854f0a741ba18d912fcfaf..a0671fe0bc81d0cf757f8660830d2cf9ab1898c8 100644 --- a/src/plugins/instantiate/tests/stdlib/oracle/free.res.oracle +++ b/src/plugins/instantiate/tests/stdlib/oracle/free.res.oracle @@ -1,5 +1,6 @@ [kernel] Parsing tests/stdlib/free.c (with preprocessing) -[instantiate] tests/stdlib/free.c:13: Warning: Ignore call: not well typed +[instantiate] tests/stdlib/free.c:13: Warning: + free instantiator cannot replace call /* Generated by Frama-C */ #include "stdlib.h" struct incomplete; diff --git a/src/plugins/instantiate/tests/stdlib/oracle/malloc.res.oracle b/src/plugins/instantiate/tests/stdlib/oracle/malloc.res.oracle index 6cec0abadff6e4e4fd12bfb6d6629c04e09816a6..9aff502467ca08d49dc7d2f346e2e05c6894c995 100644 --- a/src/plugins/instantiate/tests/stdlib/oracle/malloc.res.oracle +++ b/src/plugins/instantiate/tests/stdlib/oracle/malloc.res.oracle @@ -1,6 +1,8 @@ [kernel] Parsing tests/stdlib/malloc.c (with preprocessing) -[instantiate] tests/stdlib/malloc.c:23: Warning: Ignore call: not well typed -[instantiate] tests/stdlib/malloc.c:24: Warning: Ignore call: not well typed +[instantiate] tests/stdlib/malloc.c:23: Warning: + malloc instantiator cannot replace call +[instantiate] tests/stdlib/malloc.c:24: Warning: + malloc instantiator cannot replace call /* Generated by Frama-C */ #include "stdlib.h" struct X { diff --git a/src/plugins/instantiate/tests/stdlib/oracle/no_fc_stdlib.res.oracle b/src/plugins/instantiate/tests/stdlib/oracle/no_fc_stdlib.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..baa036c870fb4e23d59d27155db86156ea9f5bfb --- /dev/null +++ b/src/plugins/instantiate/tests/stdlib/oracle/no_fc_stdlib.res.oracle @@ -0,0 +1,253 @@ +[kernel] Parsing tests/stdlib/no_fc_stdlib.c (with preprocessing) +/* Generated by Frama-C */ +#include "stddef.h" +/*@ ghost extern int __fc_heap_status; */ + +/*@ +axiomatic dynamic_allocation { + predicate is_allocable{L}(ℤ i) + reads __fc_heap_status; + + axiom never_allocable{L}: + ∀ ℤ i; i < 0 ∧ i > 4294967295 ⇒ ¬is_allocable(i); + + } + +*/ +void *malloc(size_t s); + +void *calloc(size_t num, size_t size); + +void free(void *ptr); + +/*@ requires freeable: ptr ≡ \null ∨ \freeable(ptr); + assigns __fc_heap_status; + assigns __fc_heap_status \from __fc_heap_status, ptr; + frees ptr; + + behavior allocation: + assumes ptr ≢ \null; + ensures freed: \allocable(ptr); + assigns __fc_heap_status; + assigns __fc_heap_status \from __fc_heap_status, ptr; + frees ptr; + + behavior no_allocation: + assumes ptr ≡ \null; + assigns \nothing; + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +void free_int(int *ptr) +{ + free((void *)ptr); + return; +} + +/*@ requires correct_size: 0 ≡ size % 4; + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, num, size; + assigns __fc_heap_status \from __fc_heap_status, num, size; + allocates \result; + + behavior allocation: + assumes allocable: is_allocable(num * size); + ensures fresh_result: \fresh{Old, Here}(\result,num * size); + ensures + zero_initialization: + ∀ ℤ j0; 0 ≤ j0 < num ⇒ *(\result + j0) ≡ 0; + ensures + initialization: + ∀ ℤ j0; 0 ≤ j0 < num ⇒ \initialized(\result + j0); + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, num, size; + assigns __fc_heap_status \from __fc_heap_status, num, size; + allocates \result; + + behavior no_allocation: + assumes allocable: ¬is_allocable(num * size); + ensures null_result: \result ≡ \null; + assigns \result; + assigns \result \from \nothing; + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +int *calloc_int(size_t num, size_t size) +{ + int *__retres; + __retres = (int *)calloc(num,size); + return __retres; +} + +/*@ requires correct_size: 0 ≡ size % 4; + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, size; + assigns __fc_heap_status \from __fc_heap_status, size; + allocates \result; + + behavior allocation: + assumes allocable: is_allocable(size); + ensures fresh_result: \fresh{Old, Here}(\result,size); + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, size; + assigns __fc_heap_status \from __fc_heap_status, size; + allocates \result; + + behavior no_allocation: + assumes allocable: ¬is_allocable(size); + ensures null_result: \result ≡ \null; + assigns \result; + assigns \result \from \nothing; + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +int *malloc_int(size_t size) +{ + int *__retres; + __retres = (int *)malloc(size); + return __retres; +} + +void foo(void) +{ + int *p = malloc_int(sizeof(int)); + int *q = calloc_int((unsigned int)2,sizeof(int)); + free_int(p); + free_int(q); + return; +} + + +[kernel] Parsing tests/stdlib/result/no_fc_stdlib.c (with preprocessing) +/* Generated by Frama-C */ +#include "stddef.h" +/*@ ghost extern int __fc_heap_status; */ + +/*@ +axiomatic dynamic_allocation { + predicate is_allocable{L}(ℤ i) + reads __fc_heap_status; + + axiom never_allocable{L}: + ∀ ℤ i; i < 0 ∧ i > 4294967295 ⇒ ¬is_allocable(i); + + } + +*/ +void *malloc(size_t s); + +void *calloc(size_t num, size_t size); + +void free(void *ptr); + +/*@ requires freeable: ptr ≡ \null ∨ \freeable(ptr); + assigns __fc_heap_status; + assigns __fc_heap_status \from __fc_heap_status, ptr; + frees ptr; + + behavior allocation: + assumes ptr ≢ \null; + ensures freed: \allocable(\old(ptr)); + assigns __fc_heap_status; + assigns __fc_heap_status \from __fc_heap_status, ptr; + frees ptr; + + behavior no_allocation: + assumes ptr ≡ \null; + assigns \nothing; + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +void free_int(int *ptr) +{ + free((void *)ptr); + return; +} + +/*@ requires correct_size: 0 ≡ size % 4; + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, num, size; + assigns __fc_heap_status \from __fc_heap_status, num, size; + allocates \result; + + behavior allocation: + assumes allocable: is_allocable(num * size); + ensures + fresh_result: \fresh{Old, Here}(\result,\old(num) * \old(size)); + ensures + zero_initialization: + ∀ ℤ j0; 0 ≤ j0 < \old(num) ⇒ *(\result + j0) ≡ 0; + ensures + initialization: + ∀ ℤ j0; 0 ≤ j0 < \old(num) ⇒ \initialized(\result + j0); + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, num, size; + assigns __fc_heap_status \from __fc_heap_status, num, size; + allocates \result; + + behavior no_allocation: + assumes allocable: ¬is_allocable(num * size); + ensures null_result: \result ≡ \null; + assigns \result; + assigns \result \from \nothing; + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +int *calloc_int(size_t num, size_t size) +{ + int *__retres; + __retres = (int *)calloc(num,size); + return __retres; +} + +/*@ requires correct_size: 0 ≡ size % 4; + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, size; + assigns __fc_heap_status \from __fc_heap_status, size; + allocates \result; + + behavior allocation: + assumes allocable: is_allocable(size); + ensures fresh_result: \fresh{Old, Here}(\result,\old(size)); + assigns \result, __fc_heap_status; + assigns \result \from __fc_heap_status, size; + assigns __fc_heap_status \from __fc_heap_status, size; + allocates \result; + + behavior no_allocation: + assumes allocable: ¬is_allocable(size); + ensures null_result: \result ≡ \null; + assigns \result; + assigns \result \from \nothing; + allocates \nothing; + + complete behaviors no_allocation, allocation; + disjoint behaviors no_allocation, allocation; + */ +int *malloc_int(size_t size) +{ + int *__retres; + __retres = (int *)malloc(size); + return __retres; +} + +void foo(void) +{ + int *p = malloc_int(sizeof(int)); + int *q = calloc_int((unsigned int)2,sizeof(int)); + free_int(p); + free_int(q); + return; +} + + diff --git a/src/plugins/instantiate/tests/string/memcmp.c b/src/plugins/instantiate/tests/string/memcmp.c index 404692f9eb118b24ffa7716dceb72b990d973d2e..d8d958e45ed65cd76e23e500c531d6f498ab8c88 100644 --- a/src/plugins/instantiate/tests/string/memcmp.c +++ b/src/plugins/instantiate/tests/string/memcmp.c @@ -34,4 +34,11 @@ int with_void(void *s1, void *s2, int n){ struct incomplete ; int with_incomplete(struct incomplete* s1, struct incomplete* s2, int n){ return memcmp(s1, s2, n); -} \ No newline at end of file +} + +void with_null_or_int(int p[10]){ + memcmp(NULL, p, 10 * sizeof(int)); + memcmp(p, NULL, 10 * sizeof(int)); + memcmp((int const*)42, p, 10 * sizeof(int)); + memcmp(p, (int const*)42, 10 * sizeof(int)); +} diff --git a/src/plugins/instantiate/tests/string/memcpy.c b/src/plugins/instantiate/tests/string/memcpy.c index f2c6c03d864470e963082de31044b103dde3a930..fda5fadb75810c7a18c2549b8541046d80c68d79 100644 --- a/src/plugins/instantiate/tests/string/memcpy.c +++ b/src/plugins/instantiate/tests/string/memcpy.c @@ -41,4 +41,11 @@ struct incomplete ; void with_incomplete(struct incomplete* src, struct incomplete* dest, int n){ struct incomplete* res = memcpy(dest, src, n); memcpy(src, res, n); -} \ No newline at end of file +} + +void with_null_or_int(int p[10]){ + memcpy(NULL, p, 10 * sizeof(int)); + memcpy(p, NULL, 10 * sizeof(int)); + memcpy((int*)42, p, 10 * sizeof(int)); + memcpy(p, (int*)42, 10 * sizeof(int)); +} diff --git a/src/plugins/instantiate/tests/string/memmove.c b/src/plugins/instantiate/tests/string/memmove.c index a40698297fd597433f1ced51585f2c1176b285f7..72a5e891aeeffcfa3ec18fc5cbf372aa43734916 100644 --- a/src/plugins/instantiate/tests/string/memmove.c +++ b/src/plugins/instantiate/tests/string/memmove.c @@ -42,3 +42,10 @@ void with_incomplete(struct incomplete *src, struct incomplete *dest, int n){ struct incomplete *res = memmove(dest, src, n); memmove(src, res, n); } + +void with_null_or_int(int p[10]){ + memmove(NULL, p, 10 * sizeof(int)); + memmove(p, NULL, 10 * sizeof(int)); + memmove((int*)42, p, 10 * sizeof(int)); + memmove(p, (int*)42, 10 * sizeof(int)); +} diff --git a/src/plugins/instantiate/tests/string/memset_0.c b/src/plugins/instantiate/tests/string/memset_0.c index ffd73cad6a70f0b48b2e47fa34756d3a982456b3..bb58f3d9c3af3350257485bb6242ba931f89da4b 100644 --- a/src/plugins/instantiate/tests/string/memset_0.c +++ b/src/plugins/instantiate/tests/string/memset_0.c @@ -27,6 +27,12 @@ void integer(int dest[10]){ memset(res, 0, 10 * sizeof(int)); } +enum E { A, B, C } ; +void with_enum(enum E dest[10]){ + enum E * res = memset(dest, 0, 10 * sizeof(enum E)); + memset(res, 0, 10 * sizeof(enum E)); +} + void floats(float dest[10]){ float * res = memset(dest, 0, 10 * sizeof(float)); memset(res, 0, 10 * sizeof(float)); @@ -56,3 +62,8 @@ void with_void(void* dest){ void* res = memset(dest, 0, 10); memset(res, 0, 10); } + +void with_null_or_int(void){ + memset(NULL, 0, 10); + memset((int*) 42, 0, 10); +} diff --git a/src/plugins/instantiate/tests/string/memset_FF.c b/src/plugins/instantiate/tests/string/memset_FF.c index 17c8260b5165b3f8b6ff0fdfd04a2c5c4eabc653..68f3253fc58737341f77805794f8a567b6d000ed 100644 --- a/src/plugins/instantiate/tests/string/memset_FF.c +++ b/src/plugins/instantiate/tests/string/memset_FF.c @@ -27,6 +27,12 @@ void integer(int dest[10]){ memset(res, 0xFF, 10 * sizeof(int)); } +enum E { A, B, C } ; +void with_enum(enum E dest[10]){ + enum E * res = memset(dest, 0xFF, 10 * sizeof(enum E)); + memset(res, 0xFF, 10 * sizeof(enum E)); +} + void unsigned_integer(unsigned dest[10]){ unsigned * res = memset(dest, 0xFF, 10 * sizeof(unsigned)); memset(res, 0xFF, 10 * sizeof(unsigned)); @@ -82,3 +88,8 @@ void with_void(void* dest){ void* res = memset(dest, 0xFF, 10); memset(res, 0xFF, 10); } + +void with_null_or_int(void){ + memset(NULL, 0xFF, 10); + memset((int*) 42, 0xFF, 10); +} diff --git a/src/plugins/instantiate/tests/string/memset_value.c b/src/plugins/instantiate/tests/string/memset_value.c index 432b8ed6a6d3aa03bbb2d99e449641a6e4ac7d1c..ad966713db9b11cef6c1ed3941f92062589730d1 100644 --- a/src/plugins/instantiate/tests/string/memset_value.c +++ b/src/plugins/instantiate/tests/string/memset_value.c @@ -27,6 +27,12 @@ void integer(int dest[10], int value){ memset(res, value, 10 * sizeof(int)); } +enum E { A, B, C } ; +void with_enum(enum E dest[10], int value){ + enum E * res = memset(dest, value, 10 * sizeof(enum E)); + memset(res, value, 10 * sizeof(enum E)); +} + void with_named(named dest[10], int value){ named * res = memset(dest, value, 10 * sizeof(named)); memset(res, value, 10 * sizeof(named)); @@ -55,4 +61,9 @@ void with_void(void* dest, int value){ void with_incomplete(struct incomplete* dest, int value){ struct incomplete * res = memset(dest, value, 10); memset(res, value, 10); -} \ No newline at end of file +} + +void with_null_or_int(int value){ + memset(NULL, value, 10); + memset((int*) 42, value, 10); +} diff --git a/src/plugins/instantiate/tests/string/oracle/memcmp.res.oracle b/src/plugins/instantiate/tests/string/oracle/memcmp.res.oracle index 18ada799c0a1e0f5e274988851be469c4bc793bc..1f82bcd57b000001f672deb6a8e1f9f34dd3f699 100644 --- a/src/plugins/instantiate/tests/string/oracle/memcmp.res.oracle +++ b/src/plugins/instantiate/tests/string/oracle/memcmp.res.oracle @@ -1,6 +1,16 @@ [kernel] Parsing tests/string/memcmp.c (with preprocessing) -[instantiate] tests/string/memcmp.c:31: Warning: Ignore call: not well typed -[instantiate] tests/string/memcmp.c:36: Warning: Ignore call: not well typed +[instantiate] tests/string/memcmp.c:31: Warning: + memcmp instantiator cannot replace call +[instantiate] tests/string/memcmp.c:36: Warning: + memcmp instantiator cannot replace call +[instantiate] tests/string/memcmp.c:40: Warning: + memcmp instantiator cannot replace call +[instantiate] tests/string/memcmp.c:41: Warning: + memcmp instantiator cannot replace call +[instantiate] tests/string/memcmp.c:42: Warning: + memcmp instantiator cannot replace call +[instantiate] tests/string/memcmp.c:43: Warning: + memcmp instantiator cannot replace call /* Generated by Frama-C */ #include "stddef.h" #include "string.h" @@ -159,6 +169,17 @@ int with_incomplete(struct incomplete *s1, struct incomplete *s2, int n) return tmp; } +void with_null_or_int(int * /*[10]*/ p) +{ + memcmp((void const *)0,(void const *)p,(unsigned int)10 * sizeof(int)); + memcmp((void const *)p,(void const *)0,(unsigned int)10 * sizeof(int)); + memcmp((void const *)((int const *)42),(void const *)p, + (unsigned int)10 * sizeof(int)); + memcmp((void const *)p,(void const *)((int const *)42), + (unsigned int)10 * sizeof(int)); + return; +} + [kernel] Parsing tests/string/result/memcmp.c (with preprocessing) /* Generated by Frama-C */ @@ -328,4 +349,15 @@ int with_incomplete(struct incomplete *s1, struct incomplete *s2, int n) return tmp; } +void with_null_or_int(int *p) +{ + memcmp((void const *)0,(void const *)p,(unsigned int)10 * sizeof(int)); + memcmp((void const *)p,(void const *)0,(unsigned int)10 * sizeof(int)); + memcmp((void const *)((int const *)42),(void const *)p, + (unsigned int)10 * sizeof(int)); + memcmp((void const *)p,(void const *)((int const *)42), + (unsigned int)10 * sizeof(int)); + return; +} + diff --git a/src/plugins/instantiate/tests/string/oracle/memcpy.res.oracle b/src/plugins/instantiate/tests/string/oracle/memcpy.res.oracle index 05681aeb44ef741834b203dad7dc77150b910d34..899dd8afefc6053b12a354ddcec1ba03c5f71842 100644 --- a/src/plugins/instantiate/tests/string/oracle/memcpy.res.oracle +++ b/src/plugins/instantiate/tests/string/oracle/memcpy.res.oracle @@ -1,8 +1,20 @@ [kernel] Parsing tests/string/memcpy.c (with preprocessing) -[instantiate] tests/string/memcpy.c:36: Warning: Ignore call: not well typed -[instantiate] tests/string/memcpy.c:37: Warning: Ignore call: not well typed -[instantiate] tests/string/memcpy.c:42: Warning: Ignore call: not well typed -[instantiate] tests/string/memcpy.c:43: Warning: Ignore call: not well typed +[instantiate] tests/string/memcpy.c:36: Warning: + memcpy instantiator cannot replace call +[instantiate] tests/string/memcpy.c:37: Warning: + memcpy instantiator cannot replace call +[instantiate] tests/string/memcpy.c:42: Warning: + memcpy instantiator cannot replace call +[instantiate] tests/string/memcpy.c:43: Warning: + memcpy instantiator cannot replace call +[instantiate] tests/string/memcpy.c:47: Warning: + memcpy instantiator cannot replace call +[instantiate] tests/string/memcpy.c:48: Warning: + memcpy instantiator cannot replace call +[instantiate] tests/string/memcpy.c:49: Warning: + memcpy instantiator cannot replace call +[instantiate] tests/string/memcpy.c:50: Warning: + memcpy instantiator cannot replace call /* Generated by Frama-C */ #include "stddef.h" #include "string.h" @@ -13,16 +25,16 @@ struct X { }; typedef int named; struct incomplete; -/*@ requires aligned_end: len % 4 ≡ 0; +/*@ requires + separation: + \let __fc_len = len / 4; + \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); + requires aligned_end: len % 4 ≡ 0; requires valid_dest: \let __fc_len = len / 4; \valid(dest + (0 .. __fc_len - 1)); requires valid_read_src: \let __fc_len = len / 4; \valid_read(src + (0 .. __fc_len - 1)); - requires - separation: - \let __fc_len = len / 4; - \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); ensures copied: \let __fc_len = len / 4; @@ -53,16 +65,16 @@ void with_named(named * /*[10]*/ src, named * /*[10]*/ dest) return; } -/*@ requires aligned_end: len % 8 ≡ 0; +/*@ requires + separation: + \let __fc_len = len / 8; + \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); + requires aligned_end: len % 8 ≡ 0; requires valid_dest: \let __fc_len = len / 8; \valid(dest + (0 .. __fc_len - 1)); requires valid_read_src: \let __fc_len = len / 8; \valid_read(src + (0 .. __fc_len - 1)); - requires - separation: - \let __fc_len = len / 8; - \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); ensures copied: \let __fc_len = len / 8; @@ -86,16 +98,16 @@ void structure(struct X * /*[10]*/ src, struct X * /*[10]*/ dest) return; } -/*@ requires aligned_end: len % 4 ≡ 0; +/*@ requires + separation: + \let __fc_len = len / 4; + \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); + requires aligned_end: len % 4 ≡ 0; requires valid_dest: \let __fc_len = len / 4; \valid(dest + (0 .. __fc_len - 1)); requires valid_read_src: \let __fc_len = len / 4; \valid_read(src + (0 .. __fc_len - 1)); - requires - separation: - \let __fc_len = len / 4; - \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); ensures copied: \let __fc_len = len / 4; @@ -119,17 +131,17 @@ void pointers(int ** /*[10]*/ src, int ** /*[10]*/ dest) return; } -/*@ requires aligned_end: len % 40 ≡ 0; +/*@ requires + separation: + \let __fc_len = len / 40; + \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); + requires aligned_end: len % 40 ≡ 0; requires valid_dest: \let __fc_len = len / 40; \valid(dest + (0 .. __fc_len - 1)); requires valid_read_src: \let __fc_len = len / 40; \valid_read(src + (0 .. __fc_len - 1)); - requires - separation: - \let __fc_len = len / 40; - \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); ensures copied: \let __fc_len = len / 40; @@ -173,6 +185,15 @@ void with_incomplete(struct incomplete *src, struct incomplete *dest, int n) return; } +void with_null_or_int(int * /*[10]*/ p) +{ + memcpy((void *)0,(void const *)p,(unsigned int)10 * sizeof(int)); + memcpy((void *)p,(void const *)0,(unsigned int)10 * sizeof(int)); + memcpy((void *)((int *)42),(void const *)p,(unsigned int)10 * sizeof(int)); + memcpy((void *)p,(void const *)((int *)42),(unsigned int)10 * sizeof(int)); + return; +} + [kernel] Parsing tests/string/result/memcpy.c (with preprocessing) /* Generated by Frama-C */ @@ -185,16 +206,16 @@ struct X { }; typedef int named; struct incomplete; -/*@ requires aligned_end: len % 4 ≡ 0; +/*@ requires + separation: + \let __fc_len = len / 4; + \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); + requires aligned_end: len % 4 ≡ 0; requires valid_dest: \let __fc_len = len / 4; \valid(dest + (0 .. __fc_len - 1)); requires valid_read_src: \let __fc_len = len / 4; \valid_read(src + (0 .. __fc_len - 1)); - requires - separation: - \let __fc_len = len / 4; - \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); ensures copied: \let __fc_len = \old(len) / 4; @@ -228,16 +249,16 @@ void with_named(named *src, named *dest) return; } -/*@ requires aligned_end: len % 8 ≡ 0; +/*@ requires + separation: + \let __fc_len = len / 8; + \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); + requires aligned_end: len % 8 ≡ 0; requires valid_dest: \let __fc_len = len / 8; \valid(dest + (0 .. __fc_len - 1)); requires valid_read_src: \let __fc_len = len / 8; \valid_read(src + (0 .. __fc_len - 1)); - requires - separation: - \let __fc_len = len / 8; - \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); ensures copied: \let __fc_len = \old(len) / 8; @@ -264,16 +285,16 @@ void structure(struct X *src, struct X *dest) return; } -/*@ requires aligned_end: len % 4 ≡ 0; +/*@ requires + separation: + \let __fc_len = len / 4; + \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); + requires aligned_end: len % 4 ≡ 0; requires valid_dest: \let __fc_len = len / 4; \valid(dest + (0 .. __fc_len - 1)); requires valid_read_src: \let __fc_len = len / 4; \valid_read(src + (0 .. __fc_len - 1)); - requires - separation: - \let __fc_len = len / 4; - \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); ensures copied: \let __fc_len = \old(len) / 4; @@ -299,17 +320,17 @@ void pointers(int **src, int **dest) return; } -/*@ requires aligned_end: len % 40 ≡ 0; +/*@ requires + separation: + \let __fc_len = len / 40; + \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); + requires aligned_end: len % 40 ≡ 0; requires valid_dest: \let __fc_len = len / 40; \valid(dest + (0 .. __fc_len - 1)); requires valid_read_src: \let __fc_len = len / 40; \valid_read(src + (0 .. __fc_len - 1)); - requires - separation: - \let __fc_len = len / 40; - \separated(dest + (0 .. __fc_len - 1), src + (0 .. __fc_len - 1)); ensures copied: \let __fc_len = \old(len) / 40; @@ -356,4 +377,13 @@ void with_incomplete(struct incomplete *src, struct incomplete *dest, int n) return; } +void with_null_or_int(int *p) +{ + memcpy((void *)0,(void const *)p,(unsigned int)10 * sizeof(int)); + memcpy((void *)p,(void const *)0,(unsigned int)10 * sizeof(int)); + memcpy((void *)((int *)42),(void const *)p,(unsigned int)10 * sizeof(int)); + memcpy((void *)p,(void const *)((int *)42),(unsigned int)10 * sizeof(int)); + return; +} + diff --git a/src/plugins/instantiate/tests/string/oracle/memmove.res.oracle b/src/plugins/instantiate/tests/string/oracle/memmove.res.oracle index 15c80507c4a17b1b2c366d5ce5cccfacb4008a46..f327581499bdc3f2393d4bd573a08d587761e1df 100644 --- a/src/plugins/instantiate/tests/string/oracle/memmove.res.oracle +++ b/src/plugins/instantiate/tests/string/oracle/memmove.res.oracle @@ -1,8 +1,20 @@ [kernel] Parsing tests/string/memmove.c (with preprocessing) -[instantiate] tests/string/memmove.c:36: Warning: Ignore call: not well typed -[instantiate] tests/string/memmove.c:37: Warning: Ignore call: not well typed -[instantiate] tests/string/memmove.c:42: Warning: Ignore call: not well typed -[instantiate] tests/string/memmove.c:43: Warning: Ignore call: not well typed +[instantiate] tests/string/memmove.c:36: Warning: + memmove instantiator cannot replace call +[instantiate] tests/string/memmove.c:37: Warning: + memmove instantiator cannot replace call +[instantiate] tests/string/memmove.c:42: Warning: + memmove instantiator cannot replace call +[instantiate] tests/string/memmove.c:43: Warning: + memmove instantiator cannot replace call +[instantiate] tests/string/memmove.c:47: Warning: + memmove instantiator cannot replace call +[instantiate] tests/string/memmove.c:48: Warning: + memmove instantiator cannot replace call +[instantiate] tests/string/memmove.c:49: Warning: + memmove instantiator cannot replace call +[instantiate] tests/string/memmove.c:50: Warning: + memmove instantiator cannot replace call /* Generated by Frama-C */ #include "stddef.h" #include "string.h" @@ -157,6 +169,15 @@ void with_incomplete(struct incomplete *src, struct incomplete *dest, int n) return; } +void with_null_or_int(int * /*[10]*/ p) +{ + memmove((void *)0,(void const *)p,(unsigned int)10 * sizeof(int)); + memmove((void *)p,(void const *)0,(unsigned int)10 * sizeof(int)); + memmove((void *)((int *)42),(void const *)p,(unsigned int)10 * sizeof(int)); + memmove((void *)p,(void const *)((int *)42),(unsigned int)10 * sizeof(int)); + return; +} + [kernel] Parsing tests/string/result/memmove.c (with preprocessing) /* Generated by Frama-C */ @@ -324,4 +345,13 @@ void with_incomplete(struct incomplete *src, struct incomplete *dest, int n) return; } +void with_null_or_int(int *p) +{ + memmove((void *)0,(void const *)p,(unsigned int)10 * sizeof(int)); + memmove((void *)p,(void const *)0,(unsigned int)10 * sizeof(int)); + memmove((void *)((int *)42),(void const *)p,(unsigned int)10 * sizeof(int)); + memmove((void *)p,(void const *)((int *)42),(unsigned int)10 * sizeof(int)); + return; +} + diff --git a/src/plugins/instantiate/tests/string/oracle/memset_0.res.oracle b/src/plugins/instantiate/tests/string/oracle/memset_0.res.oracle index 1b7efe66ddfaf3924b521e046ee4ebff7779483e..dae2db7eba374181cfa6fe5705cbcd211dfeaed5 100644 --- a/src/plugins/instantiate/tests/string/oracle/memset_0.res.oracle +++ b/src/plugins/instantiate/tests/string/oracle/memset_0.res.oracle @@ -1,6 +1,12 @@ [kernel] Parsing tests/string/memset_0.c (with preprocessing) -[instantiate] tests/string/memset_0.c:56: Warning: Ignore call: not well typed -[instantiate] tests/string/memset_0.c:57: Warning: Ignore call: not well typed +[instantiate] tests/string/memset_0.c:62: Warning: + memset instantiator cannot replace call +[instantiate] tests/string/memset_0.c:63: Warning: + memset instantiator cannot replace call +[instantiate] tests/string/memset_0.c:67: Warning: + memset instantiator cannot replace call +[instantiate] tests/string/memset_0.c:68: Warning: + memset instantiator cannot replace call /* Generated by Frama-C */ #include "stddef.h" #include "string.h" @@ -10,6 +16,11 @@ struct X { int y ; }; typedef int named; +enum E { + A = 0, + B = 1, + C = 2 +}; /*@ requires in_bounds_value: -128 ≤ value < 128; requires valid_dest: \valid(ptr + (0 .. len - 1)); ensures @@ -111,6 +122,32 @@ void integer(int * /*[10]*/ dest) return; } +/*@ requires aligned_end: len % 4 ≡ 0; + requires + valid_dest: \let __fc_len = len / 4; \valid(ptr + (0 .. __fc_len - 1)); + ensures + set_content: + \let __fc_len = len / 4; + ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(ptr + j0) ≡ 0; + ensures result: \result ≡ ptr; + assigns *(ptr + (0 .. len / 4 - 1)), \result; + assigns *(ptr + (0 .. len / 4 - 1)) \from \nothing; + assigns \result \from ptr; + */ +enum E *memset_e_E_0(enum E *ptr, size_t len) +{ + enum E *__retres; + __retres = (enum E *)memset((void *)ptr,0,len); + return __retres; +} + +void with_enum(enum E * /*[10]*/ dest) +{ + enum E *res = memset_e_E_0(dest,(unsigned int)10 * sizeof(enum E)); + memset_e_E_0(res,(unsigned int)10 * sizeof(enum E)); + return; +} + /*@ requires aligned_end: len % 4 ≡ 0; requires valid_dest: \let __fc_len = len / 4; \valid(ptr + (0 .. __fc_len - 1)); @@ -233,6 +270,13 @@ void with_void(void *dest) return; } +void with_null_or_int(void) +{ + memset((void *)0,0,(unsigned int)10); + memset((void *)((int *)42),0,(unsigned int)10); + return; +} + [kernel] Parsing tests/string/result/memset_0.c (with preprocessing) /* Generated by Frama-C */ @@ -244,6 +288,11 @@ struct X { int y ; }; typedef int named; +enum E { + A = 0, + B = 1, + C = 2 +}; /*@ requires in_bounds_value: -128 ≤ value < 128; requires valid_dest: \valid(ptr + (0 .. len - 1)); ensures @@ -350,6 +399,32 @@ void integer(int *dest) return; } +/*@ requires aligned_end: len % 4 ≡ 0; + requires + valid_dest: \let __fc_len = len / 4; \valid(ptr + (0 .. __fc_len - 1)); + ensures + set_content: + \let __fc_len = \old(len) / 4; + ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(\old(ptr) + j0) ≡ 0; + ensures result: \result ≡ \old(ptr); + assigns *(ptr + (0 .. len / 4 - 1)), \result; + assigns *(ptr + (0 .. len / 4 - 1)) \from \nothing; + assigns \result \from ptr; + */ +enum E *memset_e_E_0(enum E *ptr, size_t len) +{ + enum E *__retres; + __retres = (enum E *)memset((void *)ptr,0,len); + return __retres; +} + +void with_enum(enum E *dest) +{ + enum E *res = memset_e_E_0(dest,(unsigned int)10 * sizeof(enum E)); + memset_e_E_0(res,(unsigned int)10 * sizeof(enum E)); + return; +} + /*@ requires aligned_end: len % 4 ≡ 0; requires valid_dest: \let __fc_len = len / 4; \valid(ptr + (0 .. __fc_len - 1)); @@ -473,4 +548,11 @@ void with_void(void *dest) return; } +void with_null_or_int(void) +{ + memset((void *)0,0,(unsigned int)10); + memset((void *)((int *)42),0,(unsigned int)10); + return; +} + diff --git a/src/plugins/instantiate/tests/string/oracle/memset_FF.res.oracle b/src/plugins/instantiate/tests/string/oracle/memset_FF.res.oracle index ffe160d7caa31fe89b889cdcc11c09f58f3192ab..137dd1c21a070c374f27367c3e82beb2b47a79aa 100644 --- a/src/plugins/instantiate/tests/string/oracle/memset_FF.res.oracle +++ b/src/plugins/instantiate/tests/string/oracle/memset_FF.res.oracle @@ -1,6 +1,12 @@ [kernel] Parsing tests/string/memset_FF.c (with preprocessing) -[instantiate] tests/string/memset_FF.c:82: Warning: Ignore call: not well typed -[instantiate] tests/string/memset_FF.c:83: Warning: Ignore call: not well typed +[instantiate] tests/string/memset_FF.c:88: Warning: + memset instantiator cannot replace call +[instantiate] tests/string/memset_FF.c:89: Warning: + memset instantiator cannot replace call +[instantiate] tests/string/memset_FF.c:93: Warning: + memset instantiator cannot replace call +[instantiate] tests/string/memset_FF.c:94: Warning: + memset instantiator cannot replace call /* Generated by Frama-C */ #include "stddef.h" #include "string.h" @@ -10,6 +16,11 @@ struct X { int y ; }; typedef int named; +enum E { + A = 0, + B = 1, + C = 2 +}; /*@ requires in_bounds_value: -128 ≤ value < 128; requires valid_dest: \valid(ptr + (0 .. len - 1)); ensures @@ -92,7 +103,7 @@ void nested_chars(char (* /*[10]*/ dest)[10]) ensures set_content: \let __fc_len = len / 4; - ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(ptr + j0) ≡ -2147483648; + ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(ptr + j0) ≡ ~((int)0); ensures result: \result ≡ ptr; assigns *(ptr + (0 .. len / 4 - 1)), \result; assigns *(ptr + (0 .. len / 4 - 1)) \from \nothing; @@ -112,6 +123,32 @@ void integer(int * /*[10]*/ dest) return; } +/*@ requires aligned_end: len % 4 ≡ 0; + requires + valid_dest: \let __fc_len = len / 4; \valid(ptr + (0 .. __fc_len - 1)); + ensures + set_content: + \let __fc_len = len / 4; + ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(ptr + j0) ≡ 4294967295; + ensures result: \result ≡ ptr; + assigns *(ptr + (0 .. len / 4 - 1)), \result; + assigns *(ptr + (0 .. len / 4 - 1)) \from \nothing; + assigns \result \from ptr; + */ +enum E *memset_e_E_FF(enum E *ptr, size_t len) +{ + enum E *__retres; + __retres = (enum E *)memset((void *)ptr,255,len); + return __retres; +} + +void with_enum(enum E * /*[10]*/ dest) +{ + enum E *res = memset_e_E_FF(dest,(unsigned int)10 * sizeof(enum E)); + memset_e_E_FF(res,(unsigned int)10 * sizeof(enum E)); + return; +} + /*@ requires aligned_end: len % 4 ≡ 0; requires valid_dest: \let __fc_len = len / 4; \valid(ptr + (0 .. __fc_len - 1)); @@ -145,7 +182,7 @@ void unsigned_integer(unsigned int * /*[10]*/ dest) ensures set_content: \let __fc_len = len / 4; - ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(ptr + j0) ≡ -2147483648; + ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(ptr + j0) ≡ ~((long)0); ensures result: \result ≡ ptr; assigns *(ptr + (0 .. len / 4 - 1)), \result; assigns *(ptr + (0 .. len / 4 - 1)) \from \nothing; @@ -198,8 +235,7 @@ void unsigned_long_integer(unsigned long * /*[10]*/ dest) ensures set_content: \let __fc_len = len / 8; - ∀ ℤ j0; - 0 ≤ j0 < __fc_len ⇒ *(ptr + j0) ≡ -9223372036854775808; + ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(ptr + j0) ≡ ~((long long)0); ensures result: \result ≡ ptr; assigns *(ptr + (0 .. len / 8 - 1)), \result; assigns *(ptr + (0 .. len / 8 - 1)) \from \nothing; @@ -289,7 +325,7 @@ void with_named(named * /*[10]*/ dest) \let __fc_len = len / 8; ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ - (ptr + j0)->x ≡ -2147483648 ∧ (ptr + j0)->y ≡ -2147483648; + (ptr + j0)->x ≡ ~((int)0) ∧ (ptr + j0)->y ≡ ~((int)0); ensures result: \result ≡ ptr; assigns *(ptr + (0 .. len / 8 - 1)), \result; assigns *(ptr + (0 .. len / 8 - 1)) \from \nothing; @@ -343,7 +379,7 @@ void pointers(int ** /*[10]*/ dest) \let __fc_len = len / 40; ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ - (∀ ℤ j1; 0 ≤ j1 < 10 ⇒ (*(ptr + j0))[j1] ≡ -2147483648); + (∀ ℤ j1; 0 ≤ j1 < 10 ⇒ (*(ptr + j0))[j1] ≡ ~((int)0)); ensures result: \result ≡ ptr; assigns (*(ptr + (0 .. len / 40 - 1)))[0 .. 10 - 1], \result; assigns (*(ptr + (0 .. len / 40 - 1)))[0 .. 10 - 1] \from \nothing; @@ -371,6 +407,13 @@ void with_void(void *dest) return; } +void with_null_or_int(void) +{ + memset((void *)0,0xFF,(unsigned int)10); + memset((void *)((int *)42),0xFF,(unsigned int)10); + return; +} + [kernel] Parsing tests/string/result/memset_FF.c (with preprocessing) /* Generated by Frama-C */ @@ -382,6 +425,11 @@ struct X { int y ; }; typedef int named; +enum E { + A = 0, + B = 1, + C = 2 +}; /*@ requires in_bounds_value: -128 ≤ value < 128; requires valid_dest: \valid(ptr + (0 .. len - 1)); ensures @@ -469,7 +517,7 @@ void nested_chars(char (*dest)[10]) ensures set_content: \let __fc_len = \old(len) / 4; - ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(\old(ptr) + j0) ≡ -2147483648; + ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(\old(ptr) + j0) ≡ ~((int)0); ensures result: \result ≡ \old(ptr); assigns *(ptr + (0 .. len / 4 - 1)), \result; assigns *(ptr + (0 .. len / 4 - 1)) \from \nothing; @@ -489,6 +537,32 @@ void integer(int *dest) return; } +/*@ requires aligned_end: len % 4 ≡ 0; + requires + valid_dest: \let __fc_len = len / 4; \valid(ptr + (0 .. __fc_len - 1)); + ensures + set_content: + \let __fc_len = \old(len) / 4; + ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(\old(ptr) + j0) ≡ 4294967295; + ensures result: \result ≡ \old(ptr); + assigns *(ptr + (0 .. len / 4 - 1)), \result; + assigns *(ptr + (0 .. len / 4 - 1)) \from \nothing; + assigns \result \from ptr; + */ +enum E *memset_e_E_FF(enum E *ptr, size_t len) +{ + enum E *__retres; + __retres = (enum E *)memset((void *)ptr,255,len); + return __retres; +} + +void with_enum(enum E *dest) +{ + enum E *res = memset_e_E_FF(dest,(unsigned int)10 * sizeof(enum E)); + memset_e_E_FF(res,(unsigned int)10 * sizeof(enum E)); + return; +} + /*@ requires aligned_end: len % 4 ≡ 0; requires valid_dest: \let __fc_len = len / 4; \valid(ptr + (0 .. __fc_len - 1)); @@ -522,7 +596,7 @@ void unsigned_integer(unsigned int *dest) ensures set_content: \let __fc_len = \old(len) / 4; - ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(\old(ptr) + j0) ≡ -2147483648; + ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ *(\old(ptr) + j0) ≡ ~((long)0); ensures result: \result ≡ \old(ptr); assigns *(ptr + (0 .. len / 4 - 1)), \result; assigns *(ptr + (0 .. len / 4 - 1)) \from \nothing; @@ -576,7 +650,7 @@ void unsigned_long_integer(unsigned long *dest) set_content: \let __fc_len = \old(len) / 8; ∀ ℤ j0; - 0 ≤ j0 < __fc_len ⇒ *(\old(ptr) + j0) ≡ -9223372036854775808; + 0 ≤ j0 < __fc_len ⇒ *(\old(ptr) + j0) ≡ ~((long long)0); ensures result: \result ≡ \old(ptr); assigns *(ptr + (0 .. len / 8 - 1)), \result; assigns *(ptr + (0 .. len / 8 - 1)) \from \nothing; @@ -666,8 +740,8 @@ void with_named(named *dest) \let __fc_len = \old(len) / 8; ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ - (\old(ptr) + j0)->x ≡ -2147483648 ∧ - (\old(ptr) + j0)->y ≡ -2147483648; + (\old(ptr) + j0)->x ≡ ~((int)0) ∧ + (\old(ptr) + j0)->y ≡ ~((int)0); ensures result: \result ≡ \old(ptr); assigns *(ptr + (0 .. len / 8 - 1)), \result; assigns *(ptr + (0 .. len / 8 - 1)) \from \nothing; @@ -722,7 +796,7 @@ void pointers(int **dest) ∀ ℤ j0; 0 ≤ j0 < __fc_len ⇒ (∀ ℤ j1; - 0 ≤ j1 < 10 ⇒ (*(\old(ptr) + j0))[j1] ≡ -2147483648); + 0 ≤ j1 < 10 ⇒ (*(\old(ptr) + j0))[j1] ≡ ~((int)0)); ensures result: \result ≡ \old(ptr); assigns (*(ptr + (0 .. len / 40 - 1)))[0 .. 10 - 1], \result; assigns (*(ptr + (0 .. len / 40 - 1)))[0 .. 10 - 1] \from \nothing; @@ -750,4 +824,11 @@ void with_void(void *dest) return; } +void with_null_or_int(void) +{ + memset((void *)0,0xFF,(unsigned int)10); + memset((void *)((int *)42),0xFF,(unsigned int)10); + return; +} + diff --git a/src/plugins/instantiate/tests/string/oracle/memset_nested_union.res.oracle b/src/plugins/instantiate/tests/string/oracle/memset_nested_union.res.oracle index f71268da3aab3046b86c67795177069ebc7de2f2..7185fe7a66598d4ad182720f927ea6e5f4ed4a8b 100644 --- a/src/plugins/instantiate/tests/string/oracle/memset_nested_union.res.oracle +++ b/src/plugins/instantiate/tests/string/oracle/memset_nested_union.res.oracle @@ -1,6 +1,6 @@ [kernel] Parsing tests/string/memset_nested_union.c (with preprocessing) [instantiate] tests/string/memset_nested_union.c:10: Warning: - Ignore call: not well typed + memset instantiator cannot replace call /* Generated by Frama-C */ #include "stddef.h" #include "string.h" diff --git a/src/plugins/instantiate/tests/string/oracle/memset_value.res.oracle b/src/plugins/instantiate/tests/string/oracle/memset_value.res.oracle index 462fc372857d8a254614e0759e958ffd2d99b85d..5ece8370f6baf098afc773974cb82a40f53df732 100644 --- a/src/plugins/instantiate/tests/string/oracle/memset_value.res.oracle +++ b/src/plugins/instantiate/tests/string/oracle/memset_value.res.oracle @@ -1,32 +1,40 @@ [kernel] Parsing tests/string/memset_value.c (with preprocessing) [instantiate] tests/string/memset_value.c:26: Warning: - Ignore call: not well typed + memset instantiator cannot replace call [instantiate] tests/string/memset_value.c:27: Warning: - Ignore call: not well typed -[instantiate] tests/string/memset_value.c:31: Warning: - Ignore call: not well typed + memset instantiator cannot replace call [instantiate] tests/string/memset_value.c:32: Warning: - Ignore call: not well typed -[instantiate] tests/string/memset_value.c:36: Warning: - Ignore call: not well typed + memset instantiator cannot replace call +[instantiate] tests/string/memset_value.c:33: Warning: + memset instantiator cannot replace call [instantiate] tests/string/memset_value.c:37: Warning: - Ignore call: not well typed -[instantiate] tests/string/memset_value.c:41: Warning: - Ignore call: not well typed + memset instantiator cannot replace call +[instantiate] tests/string/memset_value.c:38: Warning: + memset instantiator cannot replace call [instantiate] tests/string/memset_value.c:42: Warning: - Ignore call: not well typed -[instantiate] tests/string/memset_value.c:46: Warning: - Ignore call: not well typed + memset instantiator cannot replace call +[instantiate] tests/string/memset_value.c:43: Warning: + memset instantiator cannot replace call [instantiate] tests/string/memset_value.c:47: Warning: - Ignore call: not well typed -[instantiate] tests/string/memset_value.c:51: Warning: - Ignore call: not well typed + memset instantiator cannot replace call +[instantiate] tests/string/memset_value.c:48: Warning: + memset instantiator cannot replace call [instantiate] tests/string/memset_value.c:52: Warning: - Ignore call: not well typed -[instantiate] tests/string/memset_value.c:56: Warning: - Ignore call: not well typed + memset instantiator cannot replace call +[instantiate] tests/string/memset_value.c:53: Warning: + memset instantiator cannot replace call [instantiate] tests/string/memset_value.c:57: Warning: - Ignore call: not well typed + memset instantiator cannot replace call +[instantiate] tests/string/memset_value.c:58: Warning: + memset instantiator cannot replace call +[instantiate] tests/string/memset_value.c:62: Warning: + memset instantiator cannot replace call +[instantiate] tests/string/memset_value.c:63: Warning: + memset instantiator cannot replace call +[instantiate] tests/string/memset_value.c:67: Warning: + memset instantiator cannot replace call +[instantiate] tests/string/memset_value.c:68: Warning: + memset instantiator cannot replace call /* Generated by Frama-C */ #include "stddef.h" #include "string.h" @@ -36,6 +44,11 @@ struct X { int y ; }; typedef int named; +enum E { + A = 0, + B = 1, + C = 2 +}; struct incomplete; /*@ requires in_bounds_value: -128 ≤ value < 128; requires valid_dest: \valid(ptr + (0 .. len - 1)); @@ -119,6 +132,13 @@ void integer(int * /*[10]*/ dest, int value) return; } +void with_enum(enum E * /*[10]*/ dest, int value) +{ + enum E *res = memset((void *)dest,value,(unsigned int)10 * sizeof(enum E)); + memset((void *)res,value,(unsigned int)10 * sizeof(enum E)); + return; +} + void with_named(named * /*[10]*/ dest, int value) { named *res = memset((void *)dest,value,(unsigned int)10 * sizeof(named)); @@ -163,6 +183,13 @@ void with_incomplete(struct incomplete *dest, int value) return; } +void with_null_or_int(int value) +{ + memset((void *)0,value,(unsigned int)10); + memset((void *)((int *)42),value,(unsigned int)10); + return; +} + [kernel] Parsing tests/string/result/memset_value.c (with preprocessing) /* Generated by Frama-C */ @@ -174,6 +201,11 @@ struct X { int y ; }; typedef int named; +enum E { + A = 0, + B = 1, + C = 2 +}; struct incomplete; /*@ requires in_bounds_value: -128 ≤ value < 128; requires valid_dest: \valid(ptr + (0 .. len - 1)); @@ -262,6 +294,13 @@ void integer(int *dest, int value) return; } +void with_enum(enum E *dest, int value) +{ + enum E *res = memset((void *)dest,value,(unsigned int)10 * sizeof(enum E)); + memset((void *)res,value,(unsigned int)10 * sizeof(enum E)); + return; +} + void with_named(named *dest, int value) { named *res = memset((void *)dest,value,(unsigned int)10 * sizeof(named)); @@ -306,4 +345,11 @@ void with_incomplete(struct incomplete *dest, int value) return; } +void with_null_or_int(int value) +{ + memset((void *)0,value,(unsigned int)10); + memset((void *)((int *)42),value,(unsigned int)10); + return; +} + diff --git a/src/plugins/instantiate/transform.ml b/src/plugins/instantiate/transform.ml index 28f7a1ca81145cb2e7b414d21a0218b59ec6905f..590ee506dbdb151d26053806b4baa26e4f15d373 100644 --- a/src/plugins/instantiate/transform.ml +++ b/src/plugins/instantiate/transform.ml @@ -29,12 +29,6 @@ let register (module G: Generator_sig) = let module Instantiator = Make_instantiator(G) in Hashtbl.add base G.function_name (module Instantiator) -let mark_as_computed () = - let mark_as_computed _ instantiator = - let module I = (val instantiator: Instantiator) in I.mark_as_computed () - in - Hashtbl.iter mark_as_computed base - let get_kfs () = let get_kfs _ instantiator = let module I = (val instantiator: Instantiator) in @@ -43,6 +37,14 @@ let get_kfs () = in Hashtbl.fold (fun k v l -> (get_kfs k v) @ l) base [] +let clear () = + Global_context.clear () ; + let clear _ instantiator = + let module I = (val instantiator: Instantiator) in + I.clear () + in + Hashtbl.iter clear base + module VISet = Cil_datatype.Varinfo.Hptset class transformer = object(self) @@ -53,9 +55,9 @@ class transformer = object(self) method! vfile _ = let post f = + f.globals <- (Global_context.globals (Cil.CurrentLoc.get())) @ f.globals ; Ast.mark_as_changed () ; Ast.mark_as_grown () ; - mark_as_computed () ; f in Cil.DoChildrenPost post @@ -90,14 +92,15 @@ class transformer = object(self) method private replace_call (lval, fct, args) = try let module I = (val (self#find_enabled_instantiator fct): Instantiator) in - if I.well_typed_call lval args then - let key = I.key_from_call lval args in + if I.well_typed_call lval fct args then + let key = I.key_from_call lval fct args in let fundec = I.get_override key in let new_args = I.retype_args key args in Queue.add fundec used_instantiator_last_kf ; (fundec.svar), new_args else begin - Options.warning ~current:true "Ignore call: not well typed" ; + Options.warning + ~current:true "%s instantiator cannot replace call" fct.vname ; (fct, args) end with @@ -158,5 +161,7 @@ let compute_statuses_all_kfs () = List.iter compute_comp_disj_statuses kfs let transform file = + clear () ; Visitor.visitFramacFile (new transformer) file ; + File.reorder_ast () ; compute_statuses_all_kfs () diff --git a/tests/syntax/ast_init.ml b/tests/syntax/ast_init.ml index b0520cc04b97cac07a59159c9c944fd6722c539a..f0e57935a236f696af9949647edb7ec78d06fb81 100644 --- a/tests/syntax/ast_init.ml +++ b/tests/syntax/ast_init.ml @@ -8,6 +8,7 @@ let apply _ = (fun b -> b.bstmts <- Cil.mkStmtOneInstr (Skip (Cil_datatype.Stmt.loc s)) :: b.bstmts) l; + File.must_recompute_cfg (Kernel_function.get_definition f) ; Ast.mark_as_grown () let () = Ast.apply_after_computed apply