From b3e8e96ffe82945320eaa1c59ea8620212c068fc Mon Sep 17 00:00:00 2001 From: Valentin Perrelle <valentin.perrelle@cea.fr> Date: Fri, 17 May 2019 19:25:59 +0200 Subject: [PATCH] [Eva] Allow the partitioning to survive function returns --- src/plugins/value/engine/compute_functions.ml | 51 +++-- src/plugins/value/engine/iterator.ml | 120 +++++----- src/plugins/value/engine/iterator.mli | 3 +- src/plugins/value/engine/mem_exec.ml | 15 +- src/plugins/value/engine/mem_exec.mli | 4 +- .../value/engine/transfer_specification.ml | 8 +- .../value/engine/transfer_specification.mli | 2 +- src/plugins/value/engine/transfer_stmt.ml | 70 +++--- src/plugins/value/engine/transfer_stmt.mli | 9 +- src/plugins/value/partitioning/partition.ml | 215 +++++++++++++----- src/plugins/value/partitioning/partition.mli | 12 +- .../value/partitioning/trace_partitioning.ml | 9 +- .../value/partitioning/trace_partitioning.mli | 5 +- .../oracle/partitioning-annots.2.res.oracle | 3 - .../partitioning-interproc.0.res.oracle | 13 +- .../partitioning-interproc.1.res.oracle | 2 +- tests/value/oracle/split_return.0.res.oracle | 4 +- tests/value/oracle/split_return.1.res.oracle | 10 +- tests/value/oracle/split_return.4.res.oracle | 2 +- tests/value/partitioning-interproc.c | 2 +- 20 files changed, 333 insertions(+), 226 deletions(-) diff --git a/src/plugins/value/engine/compute_functions.ml b/src/plugins/value/engine/compute_functions.ml index a932d0eebdc..a93a27e8d51 100644 --- a/src/plugins/value/engine/compute_functions.ml +++ b/src/plugins/value/engine/compute_functions.ml @@ -164,7 +164,7 @@ module Make (Abstract: Abstractions.Eva) = struct is the instruction at which the call takes place, and is used to update the statuses of the preconditions of [kf]. If [show_progress] is true, the callstack and additional information are printed. *) - let compute_using_spec_or_body call_kinstr call recursion state = + let compute_using_spec_or_body call_kinstr call recursion pkey state = let kf = call.kf in Value_results.mark_kf_as_called kf; let global = match call_kinstr with Kglobal -> true | _ -> false in @@ -199,7 +199,8 @@ module Make (Abstract: Abstractions.Eva) = struct let vi = Kernel_function.get_vi kf in if Cil.is_in_libc vi.vattr then Library_functions.warn_unsupported_spec vi.vorig_name; - Spec.compute_using_specification ~warn:true call_kinstr call spec state, + Spec.compute_using_specification ~warn:true + call_kinstr call spec (pkey,state), Eval.Cacheable | `Def _fundec -> Db.Value.Call_Type_Value_Callbacks.apply (`Def, cvalue_state, call_stack); @@ -215,9 +216,9 @@ module Make (Abstract: Abstractions.Eva) = struct module MemExec = Mem_exec.Make (Abstract.Val) (Abstract.Dom) - let compute_and_cache_call stmt call recursion init_state = + let compute_and_cache_call stmt call recursion pkey init_state = let default () = - compute_using_spec_or_body (Kstmt stmt) call recursion init_state + compute_using_spec_or_body (Kstmt stmt) call recursion pkey init_state in if Value_parameters.MemExecAll.get () then let args = @@ -274,14 +275,14 @@ module Make (Abstract: Abstractions.Eva) = struct let rest = List.map (fun (e, assgn) -> e, lift_assigned assgn) call.rest in { call with arguments; rest } - let join_states = function + let join_states default_key = function | [] -> `Bottom - | [state] -> `Value state - | s :: l -> `Value (List.fold_left Abstract.Dom.join s l) + | (_k,s) :: l -> + `Value (default_key, List.fold_left Abstract.Dom.join s (List.map snd l)) - let compute_call_or_builtin stmt call recursion state = + let compute_call_or_builtin stmt call recursion pkey state = match Builtins.find_builtin_override call.kf with - | None -> compute_and_cache_call stmt call recursion state + | None -> compute_and_cache_call stmt call recursion pkey state | Some (name, builtin, cacheable, spec) -> Value_results.mark_kf_as_called call.kf; let kinstr = Kstmt stmt in @@ -293,11 +294,10 @@ module Make (Abstract: Abstractions.Eva) = struct (* Do not track garbled mixes created when interpreting the specification, as the result of the cvalue builtin will overwrite them. *) Locations.Location_Bytes.do_track_garbled_mix false; - let states = - Spec.compute_using_specification ~warn:false kinstr call spec state - in + let states = Spec.compute_using_specification + ~warn:false kinstr call spec (pkey,state) in Locations.Location_Bytes.do_track_garbled_mix true; - let final_state = states >>- join_states in + let final_state = join_states pkey states in let cvalue_state = Abstract.Dom.get_cvalue_or_top state in match final_state with | `Bottom -> @@ -305,24 +305,32 @@ module Make (Abstract: Abstractions.Eva) = struct Db.Value.Call_Type_Value_Callbacks.apply (`Spec spec, cvalue_state, cs); let cacheable = Eval.Cacheable in Transfer.{states; cacheable; builtin=true} - | `Value final_state -> + | `Value (pkey,final_state) -> let cvalue_call = get_cvalue_call call in let post = Abstract.Dom.get_cvalue_or_top final_state in let cvalue_states = Builtins.apply_builtin builtin cvalue_call ~pre:cvalue_state ~post in let insert cvalue_state = - Abstract.Dom.set Cvalue_domain.State.key cvalue_state final_state + pkey,Abstract.Dom.set Cvalue_domain.State.key cvalue_state final_state in - let states = Bottom.bot_of_list (List.map insert cvalue_states) in + let states = List.map insert cvalue_states in Transfer.{states; cacheable; builtin=true} + let recombine_keys compute = + fun stmt call recursion pkey state -> + let result = compute stmt call recursion Partition.Key.zero state in + let recombine (pkey',state') = + Partition.Key.recombine pkey pkey', state' + in + Transfer.{ result with states = List.map recombine result.states } + let compute_call = if Abstract.Dom.mem Cvalue_domain.State.key && Abstract.Val.mem Main_values.CVal.key && Abstract.Loc.mem Main_locations.PLoc.key - then compute_call_or_builtin - else compute_and_cache_call + then recombine_keys compute_call_or_builtin + else recombine_keys compute_and_cache_call let () = Transfer.compute_call_ref := compute_call @@ -339,11 +347,12 @@ module Make (Abstract: Abstractions.Eva) = struct let call = { kf; callstack = []; arguments = []; rest = []; return = None; } in + let pkey = Partition.Key.zero in let final_result = - compute_using_spec_or_body Kglobal call None init_state + compute_using_spec_or_body Kglobal call None pkey init_state in - let final_states = final_result.Transfer.states in - let final_state = PowersetDomain.(final_states >>-: of_list >>- join) in + let final_states = List.map snd (final_result.Transfer.states) in + let final_state = PowersetDomain.(final_states |> of_list |> join) in Value_util.pop_call_stack (); Value_parameters.feedback "done for function %a" Kernel_function.pretty kf; Abstract.Dom.Store.mark_as_computed (); diff --git a/src/plugins/value/engine/iterator.ml b/src/plugins/value/engine/iterator.ml index 933035419a6..dac195362c4 100644 --- a/src/plugins/value/engine/iterator.ml +++ b/src/plugins/value/engine/iterator.ml @@ -95,12 +95,12 @@ module Make_Dataflow (* --- Abstract values storage --- *) - module Partition = Trace_partitioning.Make (Abstract) (AnalysisParam) + module Partitioning = Trace_partitioning.Make (Abstract) (AnalysisParam) - type store = Partition.store - type flow = Partition.flow - type tank = Partition.tank - type widening = Partition.widening + type store = Partitioning.store + type flow = Partitioning.flow + type tank = Partitioning.tank + type widening = Partitioning.widening type edge_info = { mutable fireable : bool (* Does any states survive the transition ? *) @@ -141,9 +141,9 @@ module Make_Dataflow | `Value state -> state let initial_tank = - Partition.initial_tank (States.to_list initial_states) + Partitioning.initial_tank (States.to_list initial_states) let get_initial_flow () = - -1 (* Dummy edge id *), Partition.drain initial_tank + -1 (* Dummy edge id *), Partitioning.drain initial_tank let post_conditions = ref false @@ -180,11 +180,11 @@ module Make_Dataflow (* Default (Initial) stores on vertex and edges *) let default_vertex_store (v : vertex) () : store = - Partition.empty_store ~stmt:v.vertex_start_of + Partitioning.empty_store ~stmt:v.vertex_start_of let default_vertex_widening (v : vertex) () : widening = - Partition.empty_widening ~stmt:v.vertex_start_of + Partitioning.empty_widening ~stmt:v.vertex_start_of let default_edge_tank () : tank * edge_info = - Partition.empty_tank (), { fireable = false } + Partitioning.empty_tank (), { fireable = false } (* Get the stores associated to a control point or edge *) let get_vertex_store (v : vertex) : store = @@ -217,24 +217,28 @@ module Make_Dataflow (* --- Transfer functions application --- *) + type key = Partition.key type state = Domain.t - type transfer_function = state -> state list + type transfer_function = (key * state) -> (key * state) list - let id : transfer_function = fun x -> [x] + let id : transfer_function = fun (k,x) -> [(k,x)] (* Thse lifting function helps to uniformize the transfer functions to a common signature *) let lift (f : state -> state) : transfer_function = - fun x -> [f x] + fun (k,x) -> [(k,f x)] let lift' (f : state -> state or_bottom) : transfer_function = - fun x -> Bottom.to_list (f x) + fun (k,x) -> Bottom.to_list (f x >>-: fun y -> k,y) + + let lift'' (f : state -> state list) : transfer_function = + fun (k,x) -> List.map (fun y -> k,y) (f x) let sequence (f1 : transfer_function) (f2 : transfer_function) : transfer_function = - fun x -> List.fold_left (fun acc y -> f2 y @ acc) [] (f1 x) + fun (k,x) -> List.fold_left (fun acc (k',y) -> f2 (k',y) @ acc) [] (f1 (k,x)) (* Tries to evaluate \assigns … \from … clauses for assembly code. *) @@ -269,14 +273,14 @@ module Make_Dataflow if vars = [] then id else lift (Domain.leave_scope kf vars) let transfer_call (stmt : stmt) (dest : lval option) (callee : exp) - (args : exp list) (state : state) : state list = + (args : exp list) (key,state : key * state) : (key*state) list = let result, call_cacheable = - Transfer.call stmt dest callee args state + Transfer.call stmt dest callee args key state in if call_cacheable = Eval.NoCacheCallers then (* Propagate info that the current call cannot be cached either *) cacheable := Eval.NoCacheCallers; - Bottom.list_of_bot result + result let transfer_instr (stmt : stmt) (instr : instr) : transfer_function = match instr with @@ -289,13 +293,13 @@ module Make_Dataflow lift' transfer | Local_init (vi, ConsInit (f, args, k), loc) -> let kind = Abstract_domain.Local kf in - let as_func dest callee args _loc state = + let as_func dest callee args _loc (key,state) = (* This variable enters the scope too early, as it should be introduced after the call to [f] but before the assignment to [v]. This is currently not possible, at least without splitting Transfer.call in two. *) let state = Domain.enter_scope kind [vi] state in - transfer_call stmt dest callee args state + transfer_call stmt dest callee args (key,state) in Cil.treat_constructor_as_func as_func vi f args k loc | Set (dest, exp, _loc) -> @@ -331,7 +335,7 @@ module Make_Dataflow (* Assign the return value *) and assign_retval = match return_exp with - | None -> id + | None -> fun state -> [state] | Some return_exp -> let vi_ret = Option.get (Library_functions.get_retres_vi kf) in let return_lval = Var vi_ret, NoOffset in @@ -342,7 +346,7 @@ module Make_Dataflow let state' = Transfer.assign state kstmt return_lval return_exp in Bottom.to_list state' in - sequence check_postconditions assign_retval + sequence (lift'' check_postconditions) (lift'' assign_retval) let transfer_transition (t : vertex transition) : transfer_function = match t with @@ -357,7 +361,8 @@ module Make_Dataflow | Leave (block) -> transfer_leave block | Prop _ -> id (* Annotations are interpreted in [transfer_statement]. *) - let transfer_annotations (stmt : stmt) ~(record : bool) : transfer_function = + let transfer_annotations (stmt : stmt) ~(record : bool) + : state -> state list = let annots = (* We do not interpret annotations that come from statement contracts and everything previously emitted by Value (currently, alarms) *) @@ -395,20 +400,20 @@ module Make_Dataflow (transition : vertex transition) (flow : flow) : flow = (* Split return *) let flow = match transition with - | Return (return_exp, _) -> Partition.split_return flow return_exp + | Return (return_exp, _) -> Partitioning.split_return flow return_exp | _ -> flow in (* Loop transitions *) let the_stmt v = Option.get v.vertex_start_of in let enter_loop f v = - let f = Partition.enter_loop f (the_stmt v) in - Partition.transfer (lift (Domain.enter_loop (the_stmt v))) f + let f = Partitioning.enter_loop f (the_stmt v) in + Partitioning.transfer (lift (Domain.enter_loop (the_stmt v))) f and leave_loop f v = - let f = Partition.leave_loop f (the_stmt v) in - Partition.transfer (lift (Domain.leave_loop (the_stmt v))) f + let f = Partitioning.leave_loop f (the_stmt v) in + Partitioning.transfer (lift (Domain.leave_loop (the_stmt v))) f and incr_loop_counter f v = - let f = Partition.next_loop_iteration f (the_stmt v) in - Partition.transfer (lift (Domain.incr_loop_counter (the_stmt v))) f + let f = Partitioning.next_loop_iteration f (the_stmt v) in + Partitioning.transfer (lift (Domain.incr_loop_counter (the_stmt v))) f in let loops_left, loops_entered = Interpreted_automata.get_wto_index_diff kf v1 v2 @@ -422,14 +427,14 @@ module Make_Dataflow let process_edge (v1,e,v2 : G.edge) : flow = let {edge_transition=transition; edge_kinstr=kinstr} = e in let tank,edge_info = get_edge_data e in - let flow = Partition.drain tank in + let flow = Partitioning.drain tank in Db.yield (); check_signals (); current_ki := kinstr; Cil.CurrentLoc.set e.edge_loc; - let flow = Partition.transfer (transfer_transition transition) flow in + let flow = Partitioning.transfer (transfer_transition transition) flow in let flow = process_partitioning_transitions v1 v2 transition flow in - if not (Partition.is_empty_flow flow) then + if not (Partitioning.is_empty_flow flow) then edge_info.fireable <- true; flow @@ -439,7 +444,7 @@ module Make_Dataflow let call_statement_callbacks (stmt : stmt) (f : flow) : unit = (* TODO: apply on all domains. *) - let states = Partition.contents f in + let states = Partitioning.contents f in let cvalue_states = gather_cvalues states in Db.Value.Compute_Statement_Callbacks.apply (stmt, Value_util.call_stack (), cvalue_states) @@ -457,36 +462,37 @@ module Make_Dataflow (* Get vertex store *) let store = get_vertex_store v in (* Join incoming s tates *) - let flow = Partition.join sources store in + let flow = Partitioning.join sources store in let flow = match v.vertex_start_of with | Some stmt -> (* Callbacks *) call_statement_callbacks stmt flow; (* Transfer function associated to the statement *) - Partition.transfer (transfer_statement stmt) flow + Partitioning.transfer (lift'' (transfer_statement stmt)) flow | _ -> flow in (* Widen if necessary *) let flow = - if widening && not (Partition.is_empty_flow flow) then begin - let flow = Partition.widen (get_vertex_widening v) flow in + if widening && not (Partitioning.is_empty_flow flow) then begin + let flow = Partitioning.widen (get_vertex_widening v) flow in (* Try to correct over-widenings *) let correct_over_widening stmt = (* Do *not* record the status after interpreting the annotation here. Possible unproven assertions have already been recorded when the assertion has been interpreted the first time higher in this function. *) - Partition.transfer (transfer_annotations stmt ~record:false) flow + Partitioning.transfer + (lift'' (transfer_annotations stmt ~record:false)) flow in Option.fold ~some:correct_over_widening ~none:flow v.vertex_start_of end else flow in (* Dispatch to successors *) - List.iter (fun into -> Partition.fill flow ~into) (get_succ_tanks v); + List.iter (fun into -> Partitioning.fill flow ~into) (get_succ_tanks v); (* Return whether the iterator should stop or not *) - Partition.is_empty_flow flow + Partitioning.is_empty_flow flow let process_vertex ?(widening : bool = false) (v : vertex) : bool = (* Process predecessors *) @@ -509,7 +515,7 @@ module Make_Dataflow (* Try every possible successor *) let add_if_fireable (_,e,succ as edge) acc = let f = process_edge edge in - if Partition.is_empty_flow f + if Partitioning.is_empty_flow f then acc else (e.edge_key,f,succ) :: acc in @@ -525,13 +531,13 @@ module Make_Dataflow let reset_component (vertex_list : vertex list) : unit = let reset_edge (_,e,_) = let t,_ = get_edge_data e in - Partition.reset_tank t + Partitioning.reset_tank t in let reset_vertex v = let s = get_vertex_store v and w = get_vertex_widening v in - Partition.reset_store s; - Partition.reset_widening w; + Partitioning.reset_store s; + Partitioning.reset_widening w; List.iter reset_edge (G.succ_e graph v) in List.iter reset_vertex vertex_list @@ -547,7 +553,7 @@ module Make_Dataflow is especially useful for nested loops. *) if hierachical_convergence then reset_component (v :: Wto.flatten w) - else Partition.reset_widening_counter (get_vertex_widening v); + else Partitioning.reset_widening_counter (get_vertex_widening v); (* Iterate until convergence *) let iteration_count = ref 0 in while @@ -578,7 +584,7 @@ module Make_Dataflow let mark_degeneration () = let f stmt (v,_) = let l = get_succ_tanks v in - if not (List.for_all Partition.is_empty_tank l) then + if not (List.for_all Partitioning.is_empty_tank l) then Value_util.DegenerationPoints.replace stmt false in StmtTable.iter f automaton.stmt_table; @@ -594,7 +600,7 @@ module Make_Dataflow ignore (Logic.check_fct_postconditions kf active_behaviors Normal ~pre_state:initial_state ~post_states:States.empty ~result:None) - let compute () : state list or_bottom = + let compute () : (key*state) list = if interpreter_mode then simulate automaton.entry_point (get_initial_flow ()) else begin @@ -603,7 +609,7 @@ module Make_Dataflow end; if not !post_conditions then mark_postconds_as_true (); let final_store = get_vertex_store automaton.return_point in - Bottom.bot_of_list (Partition.expanded final_store) + Partitioning.expanded final_store (* --- Results conversion --- *) @@ -664,7 +670,7 @@ module Make_Dataflow let merged_states = VertexTable.create control_point_count and get_smashed_store v = let store = get_vertex_store v in - Partition.smashed store + Partitioning.smashed store in fun ~all stmt (v : vertex) -> if all || is_instr stmt @@ -685,8 +691,8 @@ module Make_Dataflow let unmerged_pre_cvalues = lazy (StmtTable.map (fun _stmt (v,_) -> let store = get_vertex_store v in - let states = Partition.expanded store in - List.map (fun x -> Domain.get_cvalue_or_top x) states) + let states = Partitioning.expanded store in + List.map (fun (_k,x) -> Domain.get_cvalue_or_top x) states) automaton.stmt_table) in let merged_pre_cvalues = lazy (lift_to_cvalues merged_pre_states) @@ -772,12 +778,10 @@ module Computer Kernel_function.pretty kf; Dataflow.merge_results (); let f = Kernel_function.get_definition kf in - (match results with - | `Value (_::_) when Cil.hasAttribute "noreturn" f.svar.vattr -> - Value_util.warning_once_current - "function %a may terminate but has the noreturn attribute" - Kernel_function.pretty kf; - | _ -> ()); + if Cil.hasAttribute "noreturn" f.svar.vattr && results <> [] then + Value_util.warning_once_current + "function %a may terminate but has the noreturn attribute" + Kernel_function.pretty kf; results, !Dataflow.cacheable in let cleanup () = diff --git a/src/plugins/value/engine/iterator.mli b/src/plugins/value/engine/iterator.mli index 163796d15e9..b76ecae19a4 100644 --- a/src/plugins/value/engine/iterator.mli +++ b/src/plugins/value/engine/iterator.mli @@ -21,7 +21,6 @@ (**************************************************************************) open Cil_types -open Eval (** Mark the analysis as aborted. It will be stopped at the next safe point *) val signal_abort: unit -> unit @@ -46,7 +45,7 @@ module Computer val compute: kernel_function -> kinstr -> Abstract.Dom.t -> - Abstract.Dom.t list or_bottom * Eval.cacheable + (Partition.key * Abstract.Dom.t) list * Eval.cacheable end diff --git a/src/plugins/value/engine/mem_exec.ml b/src/plugins/value/engine/mem_exec.ml index 7a8e0351821..54c5d3f5e9f 100644 --- a/src/plugins/value/engine/mem_exec.ml +++ b/src/plugins/value/engine/mem_exec.ml @@ -53,7 +53,7 @@ module Make incr counter; - module CallOutput = Datatype.List (Domain) + module CallOutput = Datatype.List (Datatype.Pair (Partition.Key) (Domain)) module StoredResult = Datatype.Triple @@ -145,7 +145,7 @@ module Make else expand_inputs_with_relations (count - 1) kf expanded_bases state let store_computed_call kf input_state args - (call_result: Domain.t list Bottom.or_bottom) = + (call_result: (Partition.key * Domain.t) list) = match Transfer_stmt.current_kf_inout () with | None -> () | Some inout -> @@ -196,10 +196,8 @@ module Make let all_output_bases = Extlib.opt_fold Base.Hptset.add return_base all_output_bases in - let clear state = Domain.filter kf `Post all_output_bases state in - let call_result = match call_result with - | `Bottom -> [] - | `Value list -> list + let clear (key,state) = + key, Domain.filter kf `Post all_output_bases state in let outputs = List.map clear call_result in let call_number = current_counter () in @@ -248,7 +246,8 @@ module Make let bases, outputs, i = Domain.Hashtbl.find hstates st_filtered in (* We have found a previous execution, in which the outputs are [outputs]. Copy them in [state] and return this result. *) - let process output = + let process (key,output) = + key, Domain.reuse kf bases ~current_input:state ~previous_output:output in let outputs = List.map process outputs in @@ -268,7 +267,7 @@ module Make | Not_found -> None | Result_found (outputs, i) -> let call_result = outputs in - Some (Bottom.bot_of_list call_result, i) + Some (call_result, i) end diff --git a/src/plugins/value/engine/mem_exec.mli b/src/plugins/value/engine/mem_exec.mli index afc29371ac5..cb2a641032a 100644 --- a/src/plugins/value/engine/mem_exec.mli +++ b/src/plugins/value/engine/mem_exec.mli @@ -41,7 +41,7 @@ module Make to be reused in subsequent calls *) val store_computed_call: kernel_function -> Domain.t -> Value.t or_bottom list -> - Domain.t list or_bottom -> + (Partition.key * Domain.t) list -> unit (** [reuse_previous_call kf init_state args] searches amongst the previous @@ -52,7 +52,7 @@ module Make by the plugins that have registered Value callbacks.) *) val reuse_previous_call: kernel_function -> Domain.t -> Value.t or_bottom list -> - (Domain.t list or_bottom * int) option + ((Partition.key * Domain.t) list * int) option end diff --git a/src/plugins/value/engine/transfer_specification.ml b/src/plugins/value/engine/transfer_specification.ml index 5e782e06f03..955d7456f84 100644 --- a/src/plugins/value/engine/transfer_specification.ml +++ b/src/plugins/value/engine/transfer_specification.ml @@ -564,10 +564,10 @@ module Make evaluates the assigns, and finally reduces by the post-conditions. [warn] is false for the specification of cvalue builtins — in this case, some warnings are disabled, such as warnings about new garbled mixes. *) - let compute_using_specification ~warn kinstr call spec state = + let compute_using_specification ~warn kinstr call spec (key,state) = let vi = Kernel_function.get_vi call.kf in if Cil.hasAttribute "noreturn" vi.vattr - then `Bottom + then [] else (* Initializes the variable returned by the function. *) let state = match call.return with @@ -582,8 +582,6 @@ module Make let states = compute_specification ~warn kinstr call.kf call.return spec state in - if States.is_empty states - then `Bottom - else `Value (States.to_list states) + List.map (fun x -> key,x) (States.to_list states) end diff --git a/src/plugins/value/engine/transfer_specification.mli b/src/plugins/value/engine/transfer_specification.mli index 06af47c468c..4c5a61b7767 100644 --- a/src/plugins/value/engine/transfer_specification.mli +++ b/src/plugins/value/engine/transfer_specification.mli @@ -35,6 +35,6 @@ module Make val compute_using_specification: warn:bool -> kinstr -> (Abstract.Loc.location, Abstract.Val.t) call -> spec -> - Abstract.Dom.t -> Abstract.Dom.t list or_bottom + (Partition.key * Abstract.Dom.t) -> (Partition.key * Abstract.Dom.t) list end diff --git a/src/plugins/value/engine/transfer_stmt.ml b/src/plugins/value/engine/transfer_stmt.ml index 1ce8dd5d91e..48c36f6d513 100644 --- a/src/plugins/value/engine/transfer_stmt.ml +++ b/src/plugins/value/engine/transfer_stmt.ml @@ -25,26 +25,28 @@ open Cil_datatype open Eval module type S = sig + type pkey = Partition.key type state type value type loc val assign: state -> kinstr -> lval -> exp -> state or_bottom val assume: state -> stmt -> exp -> bool -> state or_bottom val call: - stmt -> lval option -> exp -> exp list -> state -> - state list or_bottom * Eval.cacheable + stmt -> lval option -> exp -> exp list -> pkey -> state -> + (pkey*state) list * Eval.cacheable val check_unspecified_sequence: stmt -> state -> (stmt * lval list * lval list * lval list * stmt ref list) list -> unit or_bottom val enter_scope: kernel_function -> varinfo list -> state -> state type call_result = { - states: state list or_bottom; + states: (pkey * state) list; cacheable: Eval.cacheable; builtin: bool; } val compute_call_ref: - (stmt -> (loc, value) call -> recursion option ->state -> call_result) ref + (stmt -> (loc, value) call -> recursion option -> pkey -> state -> + call_result) ref end (* Reference filled in by the callwise-inout callback *) @@ -119,6 +121,7 @@ module Make (Abstract: Abstractions.Eva) = struct module Domain = Abstract.Dom module Eval = Abstract.Eval + type pkey = Partition.key type state = Domain.t type value = Value.t type loc = Location.location @@ -296,19 +299,20 @@ module Make (Abstract: Abstractions.Eva) = struct (* ------------------------------------------------------------------------ *) type call_result = { - states: state list or_bottom; + states: (pkey * state) list; cacheable: cacheable; builtin: bool; } (* Forward reference to [Eval_funs.compute_call] *) let compute_call_ref : - (stmt -> (loc, value) call -> recursion option -> state -> call_result) ref + (stmt -> (loc, value) call -> recursion option -> pkey -> state -> + call_result) ref = ref (fun _ -> assert false) (* Returns the result of a call, and a boolean that indicates whether a builtin has been used to interpret the call. *) - let process_call stmt call recursion valuation state = + let process_call stmt call recursion valuation pkey state = Value_util.push_call_stack call.kf (Kstmt stmt); let cleanup () = Value_util.pop_call_stack (); @@ -322,9 +326,9 @@ module Make (Abstract: Abstractions.Eva) = struct match Domain.start_call stmt call recursion domain_valuation state with | `Value state -> Domain.Store.register_initial_state (Value_util.call_stack ()) state; - !compute_call_ref stmt call recursion state + !compute_call_ref stmt call recursion pkey state | `Bottom -> - { states = `Bottom; cacheable = Cacheable; builtin=false } + { states = []; cacheable = Cacheable; builtin=false } in cleanup (); res @@ -455,13 +459,11 @@ module Make (Abstract: Abstractions.Eva) = struct Kernel_function.get_formals kf @ locals (* Do the call to one function. *) - let do_one_call valuation stmt lv call recursion state = + let do_one_call valuation stmt lv call recursion key state = let kf_callee = call.kf in let pre = state in (* Process the call according to the domain decision. *) - let call_result = process_call stmt call recursion valuation state in - call_result.cacheable, - call_result.states >>- fun result -> + let call_result = process_call stmt call recursion valuation key state in let leaving_vars = leaving_vars kf_callee in (* Do not try to reduce concrete arguments if a builtin was used. *) let gather_reduced_arguments = @@ -488,11 +490,11 @@ module Make (Abstract: Abstractions.Eva) = struct in let states = List.fold_left - (fun acc return -> Bottom.add_to_list (process return) acc) - [] result + (fun acc (k,x) -> Bottom.add_to_list (process x >>-: fun y -> k,y) acc) + [] call_result.states in InOutCallback.clear (); - Bottom.bot_of_list states + call_result.cacheable, states (* ------------------- Evaluation of the arguments ------------------------ *) @@ -737,7 +739,7 @@ module Make (Abstract: Abstractions.Eva) = struct (* --------------------- Process the call statement ---------------------- *) - let call stmt lval_option funcexp args state = + let call stmt lval_option funcexp args pkey state = let ki_call = Kstmt stmt in let subdivnb = subdivide_stmt stmt in (* Resolve [funcexp] into the called kernel functions. *) @@ -747,39 +749,39 @@ module Make (Abstract: Abstractions.Eva) = struct Alarmset.emit ki_call alarms; let cacheable = ref Cacheable in let eval = - functions >>- fun functions -> + functions >>-: fun functions -> let current_kf = Value_util.current_kf () in let process_one_function kf valuation = (* The special Frama_C_ functions to print states are handled here. *) if apply_special_directives ~subdivnb kf args state then let () = apply_cvalue_callback kf ki_call state in - `Value ([state]) + [(pkey,state)] else (* Create the call. *) let eval, alarms = make_call ~subdivnb kf args valuation state in Alarmset.emit ki_call alarms; - eval >>- fun (call, recursion, valuation) -> - (* Register the call. *) - Value_results.add_kf_caller call.kf ~caller:(current_kf, stmt); - (* Do the call. *) - let c, states = - do_one_call valuation stmt lval_option call recursion state + let states = eval >>-: fun (call, recursion, valuation) -> + (* Register the call. *) + Value_results.add_kf_caller call.kf ~caller:(current_kf, stmt); + (* Do the call. *) + let c, states = + do_one_call valuation stmt lval_option call recursion pkey state + in + (* If needed, propagate that callers cannot be cached. *) + if c = NoCacheCallers then + cacheable := NoCacheCallers; + states in - (* If needed, propagate that callers cannot be cached. *) - if c = NoCacheCallers then - cacheable := NoCacheCallers; - states + Bottom.list_of_bot states in (* Process each possible function apart, and append the result list. *) let process acc (kf, valuation) = - let res = process_one_function kf valuation in - (Bottom.list_of_bot res) @ acc + process_one_function kf valuation @ acc in - let states_list = List.fold_left process [] functions in - Bottom.bot_of_list states_list + List.fold_left process [] functions in - eval, !cacheable + Bottom.list_of_bot eval, !cacheable (* ------------------------------------------------------------------------ *) (* Unspecified Sequence *) diff --git a/src/plugins/value/engine/transfer_stmt.mli b/src/plugins/value/engine/transfer_stmt.mli index 87c505e2411..4be96180e16 100644 --- a/src/plugins/value/engine/transfer_stmt.mli +++ b/src/plugins/value/engine/transfer_stmt.mli @@ -27,6 +27,7 @@ val current_kf_inout: unit -> Inout_type.t option module type S = sig + type pkey = Partition.key type state type value type loc @@ -36,8 +37,8 @@ module type S = sig val assume: state -> stmt -> exp -> bool -> state or_bottom val call: - stmt -> lval option -> exp -> exp list -> state -> - state list or_bottom * Eval.cacheable + stmt -> lval option -> exp -> exp list -> pkey -> state -> + (pkey*state) list * Eval.cacheable val check_unspecified_sequence: Cil_types.stmt -> @@ -49,13 +50,13 @@ module type S = sig val enter_scope: kernel_function -> varinfo list -> state -> state type call_result = { - states: state list or_bottom; + states: (pkey * state) list; cacheable: Eval.cacheable; builtin: bool; } val compute_call_ref: - (stmt -> (loc, value) call -> recursion option -> state -> call_result) ref + (stmt -> (loc, value) call -> recursion option -> pkey -> state -> call_result) ref end module Make (Abstract: Abstractions.Eva) diff --git a/src/plugins/value/partitioning/partition.ml b/src/plugins/value/partitioning/partition.ml index 1867b8a0720..6919f7e7e73 100644 --- a/src/plugins/value/partitioning/partition.ml +++ b/src/plugins/value/partitioning/partition.ml @@ -34,6 +34,38 @@ let new_monitor ~split_limit = { split_values = Datatype.Integer.Set.empty; } +module SplitMonitor = Datatype.Make_with_collections ( + struct + open Datatype + include Serializable_undefined + + module Values = Integer.Set + + type t = split_monitor + + let name = "Partition.SplitMonitor" + + let reprs = [ new_monitor ~split_limit:0 ] + + let structural_descr = + Structural_descr.t_record [| Int.packed_descr; Values.packed_descr |] + + let compare m1 m2 = + let c = Int.compare m1.split_limit m2.split_limit in + if c <> 0 then c else Values.compare m1.split_values m2.split_values + + let equal = from_compare + + let pretty fmt m = + Format.fprintf fmt "%d/%d" (Values.cardinal m.split_values) m.split_limit + + let hash m = + FCHashtbl.hash (Int.hash m.split_limit, Values.hash m.split_values) + + let copy m = + { m with split_values = m.split_values } + end) + (* --- Stamp rationing --- *) (* Stamps used to label states according to slevel. @@ -57,24 +89,45 @@ type split_term = Eva_annotations.split_term = | Expression of Cil_types.exp | Predicate of Cil_types.predicate -module SplitTerm = struct - type t = split_term - let compare x y = - match x, y with - | Expression e1, Expression e2 -> Cil_datatype.ExpStructEq.compare e1 e2 - | Predicate p1, Predicate p2 -> Logic_utils.compare_predicate p1 p2 - | Expression _, Predicate _ -> 1 - | Predicate _, Expression _ -> -1 - - let pretty fmt = function - | Expression e -> Printer.pp_exp fmt e - | Predicate p -> Printer.pp_predicate fmt p -end +module SplitTerm = Datatype.Make_with_collections (struct + open Datatype + include Serializable_undefined -module SplitMap = Map.Make (SplitTerm) -module IntPair = Datatype.Pair (Datatype.Int) (Datatype.Int) -module LoopList = Datatype.List (IntPair) -module BranchList = Datatype.List (Datatype.Int) + module Expressions = Cil_datatype.ExpStructEq + module Predicates = Cil_datatype.PredicateStructEq + + type t = split_term + + let name = "Partition.SplitTerm" + + let reprs = + Stdlib.List.map (fun e -> Expression e) Expressions.reprs @ + Stdlib.List.map (fun p -> Predicate p) Predicates.reprs + + let structural_descr = + Structural_descr.t_sum [| + [| Expressions.packed_descr |] ; + [| Predicates.packed_descr |] |] + + let compare x y = + match x, y with + | Expression e1, Expression e2 -> Expressions.compare e1 e2 + | Predicate p1, Predicate p2 -> Logic_utils.compare_predicate p1 p2 + | Expression _, Predicate _ -> 1 + | Predicate _, Expression _ -> -1 + + let equal = from_compare + + let pretty fmt = function + | Expression e -> Printer.pp_exp fmt e + | Predicate p -> Printer.pp_predicate fmt p + + let hash = function + | Expression e -> FCHashtbl.hash (1,Expressions.hash e) + | Predicate p -> FCHashtbl.hash (2,Predicates.hash p) + end) + +module SplitMap = SplitTerm.Map type branch = int @@ -110,7 +163,14 @@ type key = { module Key = struct - type t = key + open Datatype + + module IntPair = Pair (Int) (Int) + module Stamp = Option (IntPair) + module BranchList = List (Int) + module LoopList = List (IntPair) + module Splits = SplitMap.Make (Integer) + module DSplits = SplitMap.Make (SplitMonitor) (* Initial key, before any partitioning *) let zero = { @@ -121,43 +181,88 @@ struct dynamic_splits = SplitMap.empty; } - let compare k1 k2 = - let (<?>) c (cmp,x,y) = - if c = 0 then cmp x y else c - in - Option.compare IntPair.compare k1.ration_stamp k2.ration_stamp - <?> (LoopList.compare, k1.loops, k2.loops) - <?> (SplitMap.compare Integer.compare, k1.splits, k2.splits) - <?> (SplitMap.compare (fun _ _ -> 0), k1.dynamic_splits, k2.dynamic_splits) - <?> (BranchList.compare, k1.branches, k2.branches) - - let pretty fmt key = - begin match key.ration_stamp with - | Some (n,_) -> Format.fprintf fmt "#%d" n - | None -> () - end; - Pretty_utils.pp_list ~pre:"[@[" ~sep:" ;@ " ~suf:"@]]" - Format.pp_print_int - fmt - key.branches; - Pretty_utils.pp_list ~pre:"(@[" ~sep:" ;@ " ~suf:"@])" - (fun fmt (i,_j) -> Format.pp_print_int fmt i) - fmt - key.loops; - Pretty_utils.pp_list ~pre:"{@[" ~sep:" ;@ " ~suf:"@]}" - (fun fmt (t, i) -> Format.fprintf fmt "%a:%a" - SplitTerm.pretty t - (Integer.pretty ~hexa:false) i) - fmt - (SplitMap.bindings key.splits) + include Make_with_collections (struct + include Serializable_undefined + + type t = key + + let name = "Partition.Key" + + let reprs = [ zero ] + + let structural_descr = + Structural_descr.t_record [| + Stamp.packed_descr; + BranchList.packed_descr; + LoopList.packed_descr; + Splits.packed_descr; + DSplits.packed_descr; + |] + + let compare k1 k2 = + let (<?>) c (cmp,x,y) = + if c = 0 then cmp x y else c + in + Stamp.compare k1.ration_stamp k2.ration_stamp + <?> (LoopList.compare, k1.loops, k2.loops) + <?> (Splits.compare, k1.splits, k2.splits) + (* Ignore monitors in comparison *) + <?> (SplitMap.compare (fun _ _ -> 0), k1.dynamic_splits, k2.dynamic_splits) + <?> (BranchList.compare, k1.branches, k2.branches) + + let equal = from_compare + + let hash k = + Stdlib.Hashtbl.hash ( + Stamp.hash k.ration_stamp, + BranchList.hash k.branches, + LoopList.hash k.loops, + Splits.hash k.splits, + DSplits.hash k.dynamic_splits) (* Monitors probably shouldn't be hashed *) + + let pretty fmt key = + begin match key.ration_stamp with + | Some (n,_) -> Format.fprintf fmt "#%d" n + | None -> () + end; + Pretty_utils.pp_list ~pre:"[@[" ~sep:" ;@ " ~suf:"@]]" + Format.pp_print_int + fmt + key.branches; + Pretty_utils.pp_list ~pre:"(@[" ~sep:" ;@ " ~suf:"@])" + (fun fmt (i,_j) -> Format.pp_print_int fmt i) + fmt + key.loops; + Pretty_utils.pp_list ~pre:"{@[" ~sep:" ;@ " ~suf:"@]}" + (fun fmt (t, i) -> Format.fprintf fmt "%a:%a" + SplitTerm.pretty t + Integer.pretty i) + fmt + (SplitMap.bindings key.splits) + end) let exceed_rationing key = key.ration_stamp = None + + let recombine k1 k2 = + let merge_split _ v1 v2 = + match v1, v2 with + | None, None -> None + | Some v, None | None, Some v -> Some v + | Some _v1, Some v2 -> Some v2 (* Keep the newest split value *) + in { + ration_stamp = k2.ration_stamp; + branches = k2.branches @ k1.branches; + loops = k1.loops; + splits = SplitMap.merge merge_split k1.splits k2.splits; + dynamic_splits = + SplitMap.merge merge_split k1.dynamic_splits k2.dynamic_splits; + } end (* --- Partitions --- *) -module KMap = Map.Make (Key) +module KMap = Key.Map type 'a partition = 'a KMap.t @@ -171,8 +276,8 @@ let map = KMap.map let filter = KMap.filter let merge = KMap.merge -let to_list (p : 'a partition) : 'a list = - KMap.fold (fun _k x l -> x :: l) p [] +let to_list (p : 'a partition) : (key*'a) list = + KMap.fold (fun k x l -> (k,x) :: l) p [] (* --- Partitioning actions --- *) @@ -511,20 +616,20 @@ struct in map_keys transfer p - let transfer_states (f : state -> state list) (p : t) : t = + let transfer (f : (key * state) -> (key*state) list) (p : t) : t = let n = ref 0 in let transfer acc (k,x) = - let add = + let add l (k,y) = match k.ration_stamp with (* No ration stamp, just add the state to the list *) - | None -> fun l y -> (k,y) :: l + | None -> (k,y) :: l (* There is a ration stamp, set the second part of the stamp to a unique transfer number *) - | Some (s,_) -> fun l y -> + | Some (s,_) -> let k' = { k with ration_stamp = Some (s, !n) } in incr n; (k',y) :: l in - List.fold_left add acc (f x) + List.fold_left add acc (f (k,x)) in List.fold_left transfer [] p diff --git a/src/plugins/value/partitioning/partition.mli b/src/plugins/value/partitioning/partition.mli index fe3dc9f303f..662995e4053 100644 --- a/src/plugins/value/partitioning/partition.mli +++ b/src/plugins/value/partitioning/partition.mli @@ -42,10 +42,10 @@ type key module Key : sig - val zero : key (** Initial key: no partitioning. *) - val compare : key -> key -> int - val pretty : Format.formatter -> key -> unit - val exceed_rationing: key -> bool + include Datatype.S_with_collections with type t = key + val zero : t (** Initial key: no partitioning. *) + val exceed_rationing: t -> bool + val recombine : t -> t -> t (** Recombinaison of keys after a call *) end (** Collection of states, each identified by a unique key. *) @@ -54,7 +54,7 @@ type 'state partition val empty : 'a partition val is_empty : 'a partition -> bool val size : 'a partition -> int -val to_list : 'a partition -> 'a list +val to_list : 'a partition -> (key*'a) list val find : key -> 'a partition -> 'a val replace : key -> 'a -> 'a partition -> 'a partition val merge : (key -> 'a option -> 'b option -> 'c option) -> 'a partition -> @@ -182,8 +182,8 @@ sig val union : t -> t -> t + val transfer : ((key * state) -> (key * state) list) -> t -> t val transfer_keys : t -> action -> t - val transfer_states : (state -> state list) -> t -> t val iter : (state -> unit) -> t -> unit val filter_map: (key -> state -> state option) -> t -> t diff --git a/src/plugins/value/partitioning/trace_partitioning.ml b/src/plugins/value/partitioning/trace_partitioning.ml index 9ba46bb5eef..d70eaeb3ded 100644 --- a/src/plugins/value/partitioning/trace_partitioning.ml +++ b/src/plugins/value/partitioning/trace_partitioning.ml @@ -112,13 +112,13 @@ struct (* Accessors *) - let expanded (s : store) : state list = + let expanded (s : store) : (key*state) list = Partition.to_list s.store_partition let smashed (s : store) : state or_bottom = match expanded s with | [] -> `Bottom - | v1 :: l -> `Value (List.fold_left Domain.join v1 l) + | (_k,v1) :: l -> `Value (List.fold_left Domain.join v1 (List.map snd l)) let contents (flow : flow) : state list = Flow.to_list flow @@ -210,7 +210,7 @@ struct in into.tank_states <- Partition.merge join into.tank_states new_states - let transfer = Flow.transfer_states + let transfer = Flow.transfer let output_slevel : int -> unit = let slevel_display_step = Value_parameters.ShowSlevel.get () in @@ -239,7 +239,8 @@ struct in (* Get every source flow *) let sources_states = - match sources with + (* Is there more than one non-empty incomming flow ? *) + match List.filter (fun (_b,f) -> not (Flow.is_empty f)) sources with | [(_,flow)] -> [flow] | sources -> (* Several branches -> partition according to the incoming branch *) diff --git a/src/plugins/value/partitioning/trace_partitioning.mli b/src/plugins/value/partitioning/trace_partitioning.mli index 0fbd96f2888..5c208d99b80 100644 --- a/src/plugins/value/partitioning/trace_partitioning.mli +++ b/src/plugins/value/partitioning/trace_partitioning.mli @@ -50,7 +50,7 @@ sig (* --- Accessors --- *) - val expanded : store -> state list + val expanded : store -> (Partition.key * state) list val smashed : store -> state or_bottom val contents : flow -> state list val is_empty_store : store -> bool @@ -91,7 +91,8 @@ sig val fill : into:tank -> flow -> unit (** Apply a transfer function to all the states of a propagation. *) - val transfer : (state -> state list) -> flow -> flow + val transfer : ((Partition.key * state) -> (Partition.key * state) list) -> + flow -> flow (** Join all incoming propagations into the given store. This function returns a set of states which still need to be propagated past the store. diff --git a/tests/value/oracle/partitioning-annots.2.res.oracle b/tests/value/oracle/partitioning-annots.2.res.oracle index da1dee03a86..5c65066b2aa 100644 --- a/tests/value/oracle/partitioning-annots.2.res.oracle +++ b/tests/value/oracle/partitioning-annots.2.res.oracle @@ -11,9 +11,6 @@ [eva] tests/value/partitioning-annots.c:127: function Frama_C_interval: precondition 'order' got status valid. [eva] Done for function Frama_C_interval -[eva] computing for function Frama_C_interval <- test_loop_split. - Called from tests/value/partitioning-annots.c:127. -[eva] Done for function Frama_C_interval [eva] tests/value/partitioning-annots.c:125: starting to merge loop iterations [eva] computing for function Frama_C_interval <- test_loop_split. Called from tests/value/partitioning-annots.c:127. diff --git a/tests/value/oracle/partitioning-interproc.0.res.oracle b/tests/value/oracle/partitioning-interproc.0.res.oracle index 8fdc67327c5..32cae5f4258 100644 --- a/tests/value/oracle/partitioning-interproc.0.res.oracle +++ b/tests/value/oracle/partitioning-interproc.0.res.oracle @@ -12,9 +12,9 @@ [eva] Done for function Frama_C_nondet [eva] Recording results for cassign [eva] Done for function cassign -[eva:alarm] tests/value/partitioning-interproc.c:25: Warning: - accessing uninitialized left-value. assert \initialized(&x); [eva] tests/value/partitioning-interproc.c:26: Frama_C_show_each: {1} +[eva] tests/value/partitioning-interproc.c:30: + Reusing old results for call to cassign [eva] computing for function cassign <- cassign_test. Called from tests/value/partitioning-interproc.c:30. [eva] computing for function Frama_C_nondet <- cassign <- cassign_test. @@ -22,15 +22,6 @@ [eva] Done for function Frama_C_nondet [eva] Recording results for cassign [eva] Done for function cassign -[eva] computing for function cassign <- cassign_test. - Called from tests/value/partitioning-interproc.c:30. -[eva] computing for function Frama_C_nondet <- cassign <- cassign_test. - Called from tests/value/partitioning-interproc.c:11. -[eva] Done for function Frama_C_nondet -[eva] Recording results for cassign -[eva] Done for function cassign -[eva:alarm] tests/value/partitioning-interproc.c:31: Warning: - accessing uninitialized left-value. assert \initialized(&x); [eva] tests/value/partitioning-interproc.c:32: Frama_C_show_each: {1} [eva] tests/value/partitioning-interproc.c:32: Frama_C_show_each: {1} [eva] Recording results for cassign_test diff --git a/tests/value/oracle/partitioning-interproc.1.res.oracle b/tests/value/oracle/partitioning-interproc.1.res.oracle index a2bde102b39..dfd3684a605 100644 --- a/tests/value/oracle/partitioning-interproc.1.res.oracle +++ b/tests/value/oracle/partitioning-interproc.1.res.oracle @@ -14,7 +14,7 @@ [eva:final-states] Values at end of function fabs: __retres ∈ [-0. .. 1.79769313486e+308] [eva:final-states] Values at end of function fabs_test: - x ∈ [-1.79769313486e+308 .. 1.79769313486e+308] + x ∈ [-1. .. 1.] [from] Computing for function fabs [from] Done for function fabs [from] Computing for function fabs_test diff --git a/tests/value/oracle/split_return.0.res.oracle b/tests/value/oracle/split_return.0.res.oracle index 3c39daac772..7606908946d 100644 --- a/tests/value/oracle/split_return.0.res.oracle +++ b/tests/value/oracle/split_return.0.res.oracle @@ -32,8 +32,8 @@ Called from tests/value/split_return.i:51. [eva] Recording results for f2 [eva] Done for function f2 -[eva] tests/value/split_return.i:52: Frama_C_show_each_f2: {0}, {0} [eva] tests/value/split_return.i:52: Frama_C_show_each_f2: {5; 7}, {5} +[eva] tests/value/split_return.i:52: Frama_C_show_each_f2: {0}, {0} [eva] tests/value/split_return.i:54: assertion got status valid. [eva] tests/value/split_return.i:56: Frama_C_show_each_f2_2: {5; 7}, {5} [eva] tests/value/split_return.i:57: assertion got status valid. @@ -72,8 +72,8 @@ Called from tests/value/split_return.i:120. [eva] Recording results for f5 [eva] Done for function f5 -[eva] tests/value/split_return.i:121: Frama_C_show_each_f5: {-2}, {0} [eva] tests/value/split_return.i:121: Frama_C_show_each_f5: {7}, {5} +[eva] tests/value/split_return.i:121: Frama_C_show_each_f5: {-2}, {0} [eva] tests/value/split_return.i:123: assertion got status valid. [eva] tests/value/split_return.i:125: assertion got status valid. [eva] Recording results for main5 diff --git a/tests/value/oracle/split_return.1.res.oracle b/tests/value/oracle/split_return.1.res.oracle index e161e8a2114..7410bd57efb 100644 --- a/tests/value/oracle/split_return.1.res.oracle +++ b/tests/value/oracle/split_return.1.res.oracle @@ -34,8 +34,8 @@ Called from tests/value/split_return.i:51. [eva] Recording results for f2 [eva] Done for function f2 -[eva] tests/value/split_return.i:52: Frama_C_show_each_f2: {0}, {0} [eva] tests/value/split_return.i:52: Frama_C_show_each_f2: {5; 7}, {5} +[eva] tests/value/split_return.i:52: Frama_C_show_each_f2: {0}, {0} [eva] tests/value/split_return.i:54: assertion got status valid. [eva] tests/value/split_return.i:56: Frama_C_show_each_f2_2: {5; 7}, {5} [eva] tests/value/split_return.i:57: assertion got status valid. @@ -47,8 +47,8 @@ Called from tests/value/split_return.i:76. [eva] Recording results for f3 [eva] Done for function f3 -[eva] tests/value/split_return.i:77: Frama_C_show_each_f3: {-2}, {0} [eva] tests/value/split_return.i:77: Frama_C_show_each_f3: {7}, {5} +[eva] tests/value/split_return.i:77: Frama_C_show_each_f3: {-2}, {0} [eva] tests/value/split_return.i:79: assertion got status valid. [eva] tests/value/split_return.i:81: assertion got status valid. [eva] Recording results for main3 @@ -59,8 +59,8 @@ Called from tests/value/split_return.i:97. [eva] Recording results for f4 [eva] Done for function f4 -[eva] tests/value/split_return.i:98: Frama_C_show_each_f4: {4}, {0} [eva] tests/value/split_return.i:98: Frama_C_show_each_f4: {7}, {5} +[eva] tests/value/split_return.i:98: Frama_C_show_each_f4: {4}, {0} [eva] tests/value/split_return.i:100: assertion got status valid. [eva] tests/value/split_return.i:102: assertion got status valid. [eva] Recording results for main4 @@ -71,8 +71,8 @@ Called from tests/value/split_return.i:120. [eva] Recording results for f5 [eva] Done for function f5 -[eva] tests/value/split_return.i:121: Frama_C_show_each_f5: {-2}, {0} [eva] tests/value/split_return.i:121: Frama_C_show_each_f5: {7}, {5} +[eva] tests/value/split_return.i:121: Frama_C_show_each_f5: {-2}, {0} [eva] tests/value/split_return.i:123: assertion got status valid. [eva] tests/value/split_return.i:125: assertion got status valid. [eva] Recording results for main5 @@ -104,8 +104,8 @@ Called from tests/value/split_return.i:174. [eva] Recording results for f8 [eva] Done for function f8 -[eva] tests/value/split_return.i:175: Frama_C_show_each_then8: {-1}, {0} [eva] tests/value/split_return.i:175: Frama_C_show_each_then8: {4}, {{ &x }} +[eva] tests/value/split_return.i:175: Frama_C_show_each_then8: {-1}, {0} [eva] Recording results for main8 [eva] Done for function main8 [eva] computing for function main9 <- main. diff --git a/tests/value/oracle/split_return.4.res.oracle b/tests/value/oracle/split_return.4.res.oracle index 9751f1d7147..cbcd6482358 100644 --- a/tests/value/oracle/split_return.4.res.oracle +++ b/tests/value/oracle/split_return.4.res.oracle @@ -472,8 +472,8 @@ Called from tests/value/split_return.i:51. [eva] Recording results for f2 [eva] Done for function f2 -[eva] tests/value/split_return.i:52: Frama_C_show_each_f2: {0}, {0} [eva] tests/value/split_return.i:52: Frama_C_show_each_f2: {5; 7}, {5} +[eva] tests/value/split_return.i:52: Frama_C_show_each_f2: {0}, {0} [eva] tests/value/split_return.i:56: Frama_C_show_each_f2_2: {5; 7}, {5} [eva] Recording results for main2 [eva] Done for function main2 diff --git a/tests/value/partitioning-interproc.c b/tests/value/partitioning-interproc.c index 034c5223034..1b42df1bfba 100644 --- a/tests/value/partitioning-interproc.c +++ b/tests/value/partitioning-interproc.c @@ -1,7 +1,7 @@ /* run.config* GCC: STDOPT: #"-main cassign_test -eva-partition-history 1" - STDOPT: #"-main fabs_test -eva-partition-history 1 -eva-equality-domain" + STDOPT: #"-main fabs_test -eva-partition-history 1 -eva-domains equality" */ #include "__fc_builtin.h" -- GitLab