From 232282e67a20b23f943220f68630532799d4e07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20B=C3=BChler?= <david.buhler@cea.fr> Date: Mon, 10 Jul 2023 17:31:47 +0200 Subject: [PATCH] [Eva] The allocation builtins use the new callstack type. --- .../eva/domains/cvalue/builtins_malloc.ml | 73 +++++++++---------- .../eva/domains/cvalue/builtins_malloc.mli | 8 +- .../eva/domains/cvalue/builtins_memory.ml | 2 +- .../eva/domains/cvalue/cvalue_transfer.ml | 5 +- 4 files changed, 39 insertions(+), 49 deletions(-) diff --git a/src/plugins/eva/domains/cvalue/builtins_malloc.ml b/src/plugins/eva/domains/cvalue/builtins_malloc.ml index a0072d14ed6..7700235e157 100644 --- a/src/plugins/eva/domains/cvalue/builtins_malloc.ml +++ b/src/plugins/eva/domains/cvalue/builtins_malloc.ml @@ -38,7 +38,7 @@ let wkey_imprecise_alloc = Self.register_warn_category module Base_hptmap = Hptmap.Make (Base.Base) - (Value_types.Callstack) + (Callstack) (Hptmap.Comp_unused) (struct let v = [ [ ] ] end) (struct let l = [ Ast.self ] end) @@ -57,9 +57,8 @@ let () = Ast.add_monotonic_state Dynamic_Alloc_Bases.self (* -------------------------- Auxiliary functions -------------------------- *) let current_call_site () = - match Eva_utils.legacy_call_stack () with - | (_kf, Kstmt stmt) :: _ -> stmt - | _ -> Cil.dummyStmt + let callsite = Callstack.top_callsite (Eva_utils.current_call_stack ()) in + Option.value ~default:Cil.dummyStmt callsite (* Remove some parts of the callstack: - Remove the bottom of the call tree until we get to the call site @@ -67,29 +66,26 @@ let current_call_site () = these call site correspond to a different use of a malloc function, so it is interesting to keep their bases separated. *) let call_stack_no_wrappers () = - let stack = Eva_utils.legacy_call_stack () in - assert (stack != []); - let wrappers = Parameters.AllocFunctions.get() in + let cs = Eva_utils.current_call_stack () in + let wrappers = Parameters.AllocFunctions.get () in let rec bottom_filter = function - | [] -> assert false - | [_] as stack -> stack (* Do not empty the stack completely *) + | [] | [_] as stack -> stack | (kf,_)::((kf', _):: _ as rest) as stack -> - if Datatype.String.Set.mem (Kernel_function.get_name kf) wrappers then - if Datatype.String.Set.mem (Kernel_function.get_name kf') wrappers then - bottom_filter rest - else - stack - else - stack + if Datatype.String.Set.mem (Kernel_function.get_name kf) wrappers + && Datatype.String.Set.mem (Kernel_function.get_name kf') wrappers + then bottom_filter rest + else stack in - bottom_filter stack + { cs with stack = bottom_filter cs.stack } -let register_malloced_base ?(stack=call_stack_no_wrappers ()) b = - let stack_without_top = List.tl stack in +let register_malloced_base ~stack b = + let stack_without_top = + Option.value ~default:stack (Callstack.pop stack) + in Dynamic_Alloc_Bases.set (Base_hptmap.add b stack_without_top (Dynamic_Alloc_Bases.get ())) -let fold_dynamic_bases (f: Base.t -> Value_types.Callstack.t -> 'a -> 'a) init = +let fold_dynamic_bases (f: Base.t -> Callstack.t -> 'a -> 'a) init = Base_hptmap.fold f (Dynamic_Alloc_Bases.get ()) init let is_automatically_deallocated base = @@ -120,20 +116,17 @@ let extract_size sizev_bytes = (* Name of the base that will be given to a malloced variable, determined using the callstack. *) -let base_name prefix stack = +let base_name prefix cs = let stmt_line stmt = (fst (Cil_datatype.Stmt.loc stmt)).Filepath.pos_lnum in - match stack with - | [] -> assert false - | [kf, Kglobal] -> (* Degenerate case *) - Format.asprintf "__%s_%a" prefix Kernel_function.pretty kf - | (_, Kglobal) :: _ :: _ -> assert false - | (_, Kstmt callsite) :: qstack -> + match cs.Callstack.stack with + | [] -> + (* Degenerate case *) + Format.asprintf "__%s_%a" prefix Kernel_function.pretty cs.entry_point + | (_, callsite) :: qstack -> (* Use the whole call-stack to generate the name *) let rec loop_full = function - | [_, Kglobal] -> Format.sprintf "_%s" (Kernel.MainFunction.get ()) - | (_, Kglobal) :: _ :: _ -> assert false - | [] -> assert false (* impossible, we should have seen a Kglobal *) - | (kf, Kstmt line)::b -> + | [] -> Format.sprintf "_%s" (Kernel_function.get_name cs.entry_point) + | (kf, line) :: b -> let line = stmt_line line in let node_str = Format.asprintf "_l%d__%a" line Kernel_function.pretty kf @@ -141,14 +134,14 @@ let base_name prefix stack = (loop_full b) ^ node_str in (* Use only the name of the caller to malloc for the name *) - let caller = function - | [] -> assert false (* caught above *) - | (kf, _) :: _ -> Format.asprintf "_%a" Kernel_function.pretty kf + let caller = + let kf = Callstack.top_kf { cs with stack = qstack } in + Format.asprintf "_%a" Kernel_function.pretty kf in let full_name = false in Format.asprintf "__%s%s_l%d" prefix - (if full_name then loop_full qstack else caller qstack) + (if full_name then loop_full qstack else caller) (stmt_line callsite) type var = Weak | Strong @@ -217,7 +210,7 @@ let guess_intended_malloc_type stack sizev constant_size = | _ -> raise Exit in try - match snd (List.hd stack) with + match snd (Callstack.top_call stack) with | Kstmt {skind = Instr (Call (Some lv, _, _, _))} -> mk_typed_size (Cil.typeOfLval lv) | Kstmt {skind = Instr(Local_init(vi, _, _))} -> mk_typed_size vi.vtype @@ -380,7 +373,7 @@ let string_of_region = function (* Only called when the 'weakest base' needs to be allocated. *) let create_weakest_base region = - let stack = [ fst (Globals.entry_point ()), Kglobal ] in + let stack = { (Eva_utils.current_call_stack ()) with stack = [] } in let type_base = TArray (Cil.charType, None, []) in @@ -413,8 +406,8 @@ let alloc_weakest_base region = stack. Currently, the callstacks are truncated according to [-eva-alloc-functions]. *) module MallocedByStack = (* varinfo list Callstack.hashtbl *) - State_builder.Hashtbl(Value_types.Callstack.Hashtbl) - (Datatype.List(Base)) + State_builder.Hashtbl (Callstack.Hashtbl) + (Datatype.List (Base)) (struct let name = "Value.Builtins_malloc.MallocedByStack" let size = 17 @@ -686,7 +679,7 @@ let free_automatic_bases stack state = let bases_to_free = Base_hptmap.fold (fun base stack' acc -> if is_automatically_deallocated base && - Value_types.Callstack.equal stack stack' + Callstack.equal stack stack' then Base.Hptset.add base acc else acc ) (Dynamic_Alloc_Bases.get ()) Base.Hptset.empty diff --git a/src/plugins/eva/domains/cvalue/builtins_malloc.mli b/src/plugins/eva/domains/cvalue/builtins_malloc.mli index 8cd4f9ddabf..399b01a97c6 100644 --- a/src/plugins/eva/domains/cvalue/builtins_malloc.mli +++ b/src/plugins/eva/domains/cvalue/builtins_malloc.mli @@ -23,7 +23,7 @@ (** Dynamic allocation related builtins. Most functionality is exported as builtins. *) -val fold_dynamic_bases: (Base.t -> Value_types.Callstack.t -> 'a -> 'a) -> 'a -> 'a +val fold_dynamic_bases: (Base.t -> Callstack.t -> 'a -> 'a) -> 'a -> 'a (** [fold_dynamic_bases f init] folds [f] to each dynamically allocated base, with initial accumulator [init]. Note that this also includes bases created by [alloca] and [VLAs]. *) @@ -34,7 +34,7 @@ val alloc_size_ok: Cvalue.V.t -> Alarmset.status small enough, [False] that the allocation is guaranteed to fail (because the size is always greater than SIZE_MAX). *) -val free_automatic_bases: Value_types.Callstack.t -> Cvalue.Model.t -> Cvalue.Model.t +val free_automatic_bases: Callstack.t -> Cvalue.Model.t -> Cvalue.Model.t (** Performs the equivalent of [free] for each location that was allocated via [alloca()] in the current function (as per [Eva_utils.call_stack ()]). This function must be called during finalization of a function call. *) @@ -44,7 +44,3 @@ val freeable: Cvalue.V.t -> Abstract_interp.truth value points to an allocated memory block that can be safely released using the C function free. Note that \freeable(\null) does not hold, despite NULL being a valid argument to the C function free. *) - -(**/**) -val register_malloced_base: ?stack:Value_types.Callstack.t -> Base.t -> unit -(* Should not be used by casual users. *) diff --git a/src/plugins/eva/domains/cvalue/builtins_memory.ml b/src/plugins/eva/domains/cvalue/builtins_memory.ml index fae795db083..4a34203eed4 100644 --- a/src/plugins/eva/domains/cvalue/builtins_memory.ml +++ b/src/plugins/eva/domains/cvalue/builtins_memory.ml @@ -92,7 +92,7 @@ let memcpy_check_indeterminate_offsetmap offsm = currently called function. *) let deps_nth_arg n = let open Function_Froms in - let (kf,_) = List.hd (Eva_utils.legacy_call_stack()) in + let kf = Callstack.top_kf (Eva_utils.current_call_stack ()) in try let vi = List.nth (Kernel_function.get_formals kf) n in Deps.add_data_dep Deps.bottom (Locations.zone_of_varinfo vi) diff --git a/src/plugins/eva/domains/cvalue/cvalue_transfer.ml b/src/plugins/eva/domains/cvalue/cvalue_transfer.ml index 52fb6f70d14..222f8bbe683 100644 --- a/src/plugins/eva/domains/cvalue/cvalue_transfer.ml +++ b/src/plugins/eva/domains/cvalue/cvalue_transfer.ml @@ -214,8 +214,9 @@ let finalize_call stmt call _recursion ~pre:_ ~post:state = To minimize computations, only do it for function definitions. *) let state' = if Kernel_function.is_definition call.kf then - let stack = (call.kf, Kstmt stmt) :: (Eva_utils.legacy_call_stack ()) in - Builtins_malloc.free_automatic_bases stack state + let callstack = Eva_utils.current_call_stack () in + let callstack = Callstack.push call.kf stmt callstack in + Builtins_malloc.free_automatic_bases callstack state else state in `Value state' -- GitLab