From ac00a6ecddf22bac391ac28f87d309c7d9cdfbad Mon Sep 17 00:00:00 2001 From: Allan Blanchard <allan.blanchard@cea.fr> Date: Thu, 26 Mar 2020 15:30:46 +0100 Subject: [PATCH] [Instantiate] Refacto in string modules --- src/plugins/instantiate/Makefile.in | 1 + src/plugins/instantiate/basic_blocks.ml | 11 ++ src/plugins/instantiate/basic_blocks.mli | 5 + src/plugins/instantiate/string/mem_utils.ml | 150 ++++++++++++++++++ src/plugins/instantiate/string/mem_utils.mli | 60 +++++++ src/plugins/instantiate/string/memcmp.ml | 83 ++-------- src/plugins/instantiate/string/memcpy.ml | 118 +++----------- src/plugins/instantiate/string/memmove.ml | 116 ++------------ .../oracle/ignore-functions.res.oracle | 10 +- .../options/oracle/only-functions.res.oracle | 10 +- .../tests/string/oracle/memcpy.res.oracle | 80 +++++----- 11 files changed, 332 insertions(+), 312 deletions(-) create mode 100644 src/plugins/instantiate/string/mem_utils.ml create mode 100644 src/plugins/instantiate/string/mem_utils.mli diff --git a/src/plugins/instantiate/Makefile.in b/src/plugins/instantiate/Makefile.in index 144f5c7128e..a8fc2764589 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 \ diff --git a/src/plugins/instantiate/basic_blocks.ml b/src/plugins/instantiate/basic_blocks.ml index 660db8c83c0..830911e482e 100644 --- a/src/plugins/instantiate/basic_blocks.ml +++ b/src/plugins/instantiate/basic_blocks.ml @@ -50,6 +50,17 @@ let call_function lval vi args = let args = List.map2 gen_arg args typs in Call(lval, (Cil.evar vi), args, loc) +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)) -> Some (Cil.typeOf x) + | _ -> None + else + let xt = Cil.unrollTypeDeep (Cil.typeOf no_cast) in + let xt = Cil.type_remove_qualifier_attributes_deep xt in + Some (Cil.typeOf_pointed xt) + let rec string_of_typ_aux = function | TVoid(_) -> "void" | TInt(IBool, _) -> "bool" diff --git a/src/plugins/instantiate/basic_blocks.mli b/src/plugins/instantiate/basic_blocks.mli index 8b22347ecc1..d8723d96765 100644 --- a/src/plugins/instantiate/basic_blocks.mli +++ b/src/plugins/instantiate/basic_blocks.mli @@ -42,6 +42,11 @@ val ttype_of_pointed: logic_type -> logic_type (** {2 C} *) +(** For an expression, return the type of the pointed data. + If the expression is not a pointer, returns None. +*) +val exp_type_of_pointed: exp -> typ option + (** For a type [T], returns [T*] *) val ptr_of: typ -> typ diff --git a/src/plugins/instantiate/string/mem_utils.ml b/src/plugins/instantiate/string/mem_utils.ml new file mode 100644 index 00000000000..71247c78162 --- /dev/null +++ b/src/plugins/instantiate/string/mem_utils.ml @@ -0,0 +1,150 @@ +(**************************************************************************) +(* *) +(* 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 | Len | Int +type action = Strip | Id +type param = string * kind * action +type proto = kind * param list +type 'a spec_gen = location -> typ -> term -> term -> term -> 'a + +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: 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 + | Len -> size_t() + | Int -> Cil.intType + 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 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 + | _, (Len | Int), _ -> Some (Cil.typeOf e) + in + let lvt = Extlib.opt_map Cil.typeOfLval lval in + let pts = List.map2 extract args ps in + let is_none = function None -> true | _ -> false in + if List.exists is_none pts then false + else F.well_typed lvt (List.map (fun x -> Extlib.the x) 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 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 + | Some t -> t + | None -> + 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 00000000000..543e5b06bc1 --- /dev/null +++ b/src/plugins/instantiate/string/mem_utils.mli @@ -0,0 +1,60 @@ +(**************************************************************************) +(* *) +(* 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 | Len | Int +type action = Strip | Id +type param = string * kind * action +type proto = kind * param list + +module type Function = sig + val name: string + val prototype: proto + 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 -> exp list -> bool + val retype_args : 'a -> exp list -> exp list + val key_from_call : 'a -> 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 diff --git a/src/plugins/instantiate/string/memcmp.ml b/src/plugins/instantiate/string/memcmp.ml index 633294db95b..c8518480ed8 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,31 @@ 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 generate_spec = Mem_utils.mem2s_spec ~requires ~assigns ~ensures -let args_for_original _t args = args +module Function = +struct + open Mem_utils + let name = function_name + let prototype = Int, [ ("s1",CPtr,Strip);("s2",CPtr,Strip);("len",Len,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 d0db608eef1..b13a13067cb 100644 --- a/src/plugins/instantiate/string/memcpy.ml +++ b/src/plugins/instantiate/string/memcpy.ml @@ -23,118 +23,42 @@ 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" + separated :: (memcpy_memmove_common_requires loc t dest src len) -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 assigns = memcpy_memmove_common_assigns +let ensures = memcpy_memmove_common_ensures "copied" +let generate_spec = mem2s_spec ~requires ~assigns ~ensures -let args_for_original _t args = args +module Function = +struct + let name = function_name + let prototype = Ptr, [("dest",Ptr,Strip);("src",CPtr,Strip);("len",Len,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 6481c423a1f..0295236f2cd 100644 --- a/src/plugins/instantiate/string/memmove.ml +++ b/src/plugins/instantiate/string/memmove.ml @@ -21,114 +21,32 @@ (**************************************************************************) 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 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 -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 +module Function = +struct + let name = function_name + let prototype = Ptr, [("dest",Ptr,Strip);("src",CPtr,Strip);("len",Len,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/tests/options/oracle/ignore-functions.res.oracle b/src/plugins/instantiate/tests/options/oracle/ignore-functions.res.oracle index 8aacf1fa757..b260fc61afd 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 cc08c601aac..d84cec92ebc 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/string/oracle/memcpy.res.oracle b/src/plugins/instantiate/tests/string/oracle/memcpy.res.oracle index 05681aeb44e..78076d88eb1 100644 --- a/src/plugins/instantiate/tests/string/oracle/memcpy.res.oracle +++ b/src/plugins/instantiate/tests/string/oracle/memcpy.res.oracle @@ -13,16 +13,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 +53,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 +86,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 +119,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; @@ -185,16 +185,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 +228,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 +264,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 +299,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; -- GitLab