|
|
|
@ -12,7 +12,7 @@ open PulseDomainInterface
|
|
|
|
|
type arg_payload = AbstractValue.t * ValueHistory.t
|
|
|
|
|
|
|
|
|
|
type model =
|
|
|
|
|
caller_summary:Summary.t
|
|
|
|
|
PulseSummary.t InterproceduralAnalysis.t
|
|
|
|
|
-> callee_procname:Procname.t
|
|
|
|
|
-> Location.t
|
|
|
|
|
-> ret:Ident.t * Typ.t
|
|
|
|
@ -21,7 +21,7 @@ type model =
|
|
|
|
|
|
|
|
|
|
module Misc = struct
|
|
|
|
|
let shallow_copy model_desc dest_pointer_hist src_pointer_hist : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model model_desc; location; in_call= []} in
|
|
|
|
|
let* astate, obj = PulseOperations.eval_access location src_pointer_hist Dereference astate in
|
|
|
|
|
let* astate, obj_copy = PulseOperations.shallow_copy location obj astate in
|
|
|
|
@ -35,12 +35,11 @@ module Misc = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let early_exit : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ _ ~ret:_ astate ->
|
|
|
|
|
Ok [ExecutionDomain.ExitProgram astate]
|
|
|
|
|
fun _ ~callee_procname:_ _ ~ret:_ astate -> Ok [ExecutionDomain.ExitProgram astate]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let return_int : Int64.t -> model =
|
|
|
|
|
fun i64 ~caller_summary:_ ~callee_procname:_ _location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun i64 _ ~callee_procname:_ _location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let i = IntLit.of_int64 i64 in
|
|
|
|
|
let ret_addr = AbstractValue.Constants.get_int i in
|
|
|
|
|
let astate = PulseArithmetic.and_eq_int ret_addr i astate in
|
|
|
|
@ -48,30 +47,28 @@ module Misc = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let return_unknown_size : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ _location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ _location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let ret_addr = AbstractValue.mk_fresh () in
|
|
|
|
|
let astate = PulseArithmetic.and_nonnegative ret_addr astate in
|
|
|
|
|
PulseOperations.write_id ret_id (ret_addr, []) astate |> PulseOperations.ok_continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let skip : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ _ ~ret:_ astate -> PulseOperations.ok_continue astate
|
|
|
|
|
|
|
|
|
|
let skip : model = fun _ ~callee_procname:_ _ ~ret:_ astate -> PulseOperations.ok_continue astate
|
|
|
|
|
|
|
|
|
|
let nondet ~fn_name : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model fn_name; location; in_call= []} in
|
|
|
|
|
PulseOperations.havoc_id ret_id [event] astate |> PulseOperations.ok_continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let id_first_arg arg_access_hist : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ _ ~ret astate ->
|
|
|
|
|
fun _ ~callee_procname:_ _ ~ret astate ->
|
|
|
|
|
PulseOperations.write_id (fst ret) arg_access_hist astate |> PulseOperations.ok_continue
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module C = struct
|
|
|
|
|
let free deleted_access : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
(* NOTE: we could introduce a case-split explicitly on =0 vs ≠0 but instead only act on what we
|
|
|
|
|
currently know about the value. This is purely to avoid contributing to path explosion. *)
|
|
|
|
|
(* freeing 0 is a no-op *)
|
|
|
|
@ -84,7 +81,7 @@ module C = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let malloc _ : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let ret_addr = AbstractValue.mk_fresh () in
|
|
|
|
|
let ret_value =
|
|
|
|
|
(ret_addr, [ValueHistory.Allocation {f= Model (Procname.to_string callee_procname); location}])
|
|
|
|
@ -102,7 +99,7 @@ module C = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let malloc_not_null _ : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let ret_addr = AbstractValue.mk_fresh () in
|
|
|
|
|
let ret_value =
|
|
|
|
|
(ret_addr, [ValueHistory.Allocation {f= Model (Procname.to_string callee_procname); location}])
|
|
|
|
@ -114,14 +111,14 @@ module C = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let cf_bridging_release access : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ _ ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ _ ~ret:(ret_id, _) astate ->
|
|
|
|
|
let astate = PulseOperations.write_id ret_id access astate in
|
|
|
|
|
PulseOperations.remove_allocation_attr (fst access) astate |> PulseOperations.ok_continue
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module Cplusplus = struct
|
|
|
|
|
let delete deleted_access : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
let+ astate =
|
|
|
|
|
PulseOperations.invalidate location Invalidation.CppDelete deleted_access astate
|
|
|
|
|
in
|
|
|
|
@ -129,7 +126,7 @@ module Cplusplus = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let placement_new actuals : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "<placement new>()"; location; in_call= []} in
|
|
|
|
|
( match List.rev actuals with
|
|
|
|
|
| ProcnameDispatcher.Call.FuncArg.{arg_payload= address, hist} :: _ ->
|
|
|
|
@ -156,7 +153,7 @@ module StdAtomicInteger = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let constructor this_address init_value : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::atomic::atomic()"; location; in_call= []} in
|
|
|
|
|
let this = (AbstractValue.mk_fresh (), [event]) in
|
|
|
|
|
let* astate, int_field =
|
|
|
|
@ -181,7 +178,7 @@ module StdAtomicInteger = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let fetch_add this (increment, _) _memory_ordering : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::atomic::fetch_add()"; location; in_call= []} in
|
|
|
|
|
let+ astate =
|
|
|
|
|
arith_bop `Post location event ret_id (PlusA None) this (AbstractValueOperand increment)
|
|
|
|
@ -191,7 +188,7 @@ module StdAtomicInteger = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let fetch_sub this (increment, _) _memory_ordering : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::atomic::fetch_sub()"; location; in_call= []} in
|
|
|
|
|
let+ astate =
|
|
|
|
|
arith_bop `Post location event ret_id (MinusA None) this (AbstractValueOperand increment)
|
|
|
|
@ -201,7 +198,7 @@ module StdAtomicInteger = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let operator_plus_plus_pre this : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::atomic::operator++()"; location; in_call= []} in
|
|
|
|
|
let+ astate =
|
|
|
|
|
arith_bop `Pre location event ret_id (PlusA None) this (LiteralOperand IntLit.one) astate
|
|
|
|
@ -210,7 +207,7 @@ module StdAtomicInteger = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let operator_plus_plus_post this _int : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event =
|
|
|
|
|
ValueHistory.Call {f= Model "std::atomic<T>::operator++(T)"; location; in_call= []}
|
|
|
|
|
in
|
|
|
|
@ -221,7 +218,7 @@ module StdAtomicInteger = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let operator_minus_minus_pre this : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::atomic::operator--()"; location; in_call= []} in
|
|
|
|
|
let+ astate =
|
|
|
|
|
arith_bop `Pre location event ret_id (MinusA None) this (LiteralOperand IntLit.one) astate
|
|
|
|
@ -230,7 +227,7 @@ module StdAtomicInteger = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let operator_minus_minus_post this _int : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event =
|
|
|
|
|
ValueHistory.Call {f= Model "std::atomic<T>::operator--(T)"; location; in_call= []}
|
|
|
|
|
in
|
|
|
|
@ -241,7 +238,7 @@ module StdAtomicInteger = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let load_instr model_desc this _memory_ordering_opt : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model model_desc; location; in_call= []} in
|
|
|
|
|
let+ astate, _int_addr, (int, hist) = load_backing_int location this astate in
|
|
|
|
|
let astate = PulseOperations.write_id ret_id (int, event :: hist) astate in
|
|
|
|
@ -261,14 +258,14 @@ module StdAtomicInteger = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let store this_address (new_value, new_hist) _memory_ordering : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::atomic::store()"; location; in_call= []} in
|
|
|
|
|
let+ astate = store_backing_int location this_address (new_value, event :: new_hist) astate in
|
|
|
|
|
[ExecutionDomain.ContinueProgram astate]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let exchange this_address (new_value, new_hist) _memory_ordering : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::atomic::exchange()"; location; in_call= []} in
|
|
|
|
|
let* astate, _int_addr, (old_int, old_hist) = load_backing_int location this_address astate in
|
|
|
|
|
let+ astate = store_backing_int location this_address (new_value, event :: new_hist) astate in
|
|
|
|
@ -279,7 +276,7 @@ end
|
|
|
|
|
module JavaObject = struct
|
|
|
|
|
(* naively modeled as shallow copy. *)
|
|
|
|
|
let clone src_pointer_hist : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "Object.clone"; location; in_call= []} in
|
|
|
|
|
let* astate, obj = PulseOperations.eval_access location src_pointer_hist Dereference astate in
|
|
|
|
|
let+ astate, obj_copy = PulseOperations.shallow_copy location obj astate in
|
|
|
|
@ -301,7 +298,7 @@ module StdBasicString = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let data this_hist : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:(ret_id, _) astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::basic_string::data()"; location; in_call= []} in
|
|
|
|
|
let* astate, string_addr_hist = to_internal_string location this_hist astate in
|
|
|
|
|
let+ astate, (string, hist) =
|
|
|
|
@ -312,7 +309,7 @@ module StdBasicString = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let destructor this_hist : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
let model = CallEvent.Model "std::basic_string::~basic_string()" in
|
|
|
|
|
let call_event = ValueHistory.Call {f= model; location; in_call= []} in
|
|
|
|
|
let* astate, (string_addr, string_hist) = to_internal_string location this_hist astate in
|
|
|
|
@ -326,7 +323,7 @@ end
|
|
|
|
|
|
|
|
|
|
module StdFunction = struct
|
|
|
|
|
let operator_call lambda_ptr_hist actuals : model =
|
|
|
|
|
fun ~caller_summary ~callee_procname:_ location ~ret astate ->
|
|
|
|
|
fun {analyze_dependency} ~callee_procname:_ location ~ret astate ->
|
|
|
|
|
let havoc_ret (ret_id, _) astate =
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::function::operator()"; location; in_call= []} in
|
|
|
|
|
[PulseOperations.havoc_id ret_id [event] astate]
|
|
|
|
@ -344,8 +341,9 @@ module StdFunction = struct
|
|
|
|
|
List.map actuals ~f:(fun ProcnameDispatcher.Call.FuncArg.{arg_payload; typ} ->
|
|
|
|
|
(arg_payload, typ) )
|
|
|
|
|
in
|
|
|
|
|
PulseOperations.call ~caller_summary location callee_proc_name ~ret ~actuals
|
|
|
|
|
~formals_opt:None astate
|
|
|
|
|
PulseOperations.call
|
|
|
|
|
~callee_data:(analyze_dependency callee_proc_name)
|
|
|
|
|
location callee_proc_name ~ret ~actuals ~formals_opt:None astate
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module GenericArrayBackedCollection = struct
|
|
|
|
@ -384,7 +382,7 @@ module GenericArrayBackedCollectionIterator = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let constructor ~desc this init : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model desc; location; in_call= []} in
|
|
|
|
|
let* astate, (arr_addr, arr_hist) = GenericArrayBackedCollection.eval location init astate in
|
|
|
|
|
let* astate =
|
|
|
|
@ -399,7 +397,7 @@ module GenericArrayBackedCollectionIterator = struct
|
|
|
|
|
>>| ExecutionDomain.continue >>| List.return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let operator_star ~desc iter ~caller_summary:_ ~callee_procname:_ location ~ret astate =
|
|
|
|
|
let operator_star ~desc iter _ ~callee_procname:_ location ~ret astate =
|
|
|
|
|
let event = ValueHistory.Call {f= Model desc; location; in_call= []} in
|
|
|
|
|
let* astate, (iter_index_addr, iter_index_hist) = to_internal_pointer location iter astate in
|
|
|
|
|
let+ astate, (elem_val, _) =
|
|
|
|
@ -409,7 +407,7 @@ module GenericArrayBackedCollectionIterator = struct
|
|
|
|
|
[ExecutionDomain.ContinueProgram astate]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let operator_plus_plus ~desc iter ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate =
|
|
|
|
|
let operator_plus_plus ~desc iter _ ~callee_procname:_ location ~ret:_ astate =
|
|
|
|
|
let event = ValueHistory.Call {f= Model desc; location; in_call= []} in
|
|
|
|
|
let index_next = AbstractValue.mk_fresh () in
|
|
|
|
|
let* astate, (current_index, current_index_hist) = to_internal_pointer location iter astate in
|
|
|
|
@ -435,8 +433,7 @@ module StdVector = struct
|
|
|
|
|
>>= PulseOperations.havoc_field location vector GenericArrayBackedCollection.field trace
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let init_list_constructor this init_list ~caller_summary:_ ~callee_procname:_ location ~ret:_
|
|
|
|
|
astate =
|
|
|
|
|
let init_list_constructor this init_list _ ~callee_procname:_ location ~ret:_ astate =
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::vector::vector()"; location; in_call= []} in
|
|
|
|
|
let* astate, init_copy = PulseOperations.shallow_copy location init_list astate in
|
|
|
|
|
let+ astate =
|
|
|
|
@ -448,7 +445,7 @@ module StdVector = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let invalidate_references vector_f vector : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
let crumb =
|
|
|
|
|
ValueHistory.Call
|
|
|
|
|
{ f= Model (Format.asprintf "%a()" Invalidation.pp_std_vector_function vector_f)
|
|
|
|
@ -460,7 +457,7 @@ module StdVector = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let at ~desc vector index : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model desc; location; in_call= []} in
|
|
|
|
|
let+ astate, (addr, hist) =
|
|
|
|
|
GenericArrayBackedCollection.element location vector (fst index) astate
|
|
|
|
@ -470,7 +467,7 @@ module StdVector = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let vector_begin vector iter : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "std::vector::begin()"; location; in_call= []} in
|
|
|
|
|
let index_zero = AbstractValue.mk_fresh () in
|
|
|
|
|
let astate = PulseArithmetic.and_eq_int index_zero IntLit.zero astate in
|
|
|
|
@ -488,7 +485,7 @@ module StdVector = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let reserve vector : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
let crumb = ValueHistory.Call {f= Model "std::vector::reserve()"; location; in_call= []} in
|
|
|
|
|
reallocate_internal_array [crumb] vector Reserve location astate
|
|
|
|
|
>>| AddressAttributes.std_vector_reserve (fst vector)
|
|
|
|
@ -496,7 +493,7 @@ module StdVector = struct
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let push_back vector : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret:_ astate ->
|
|
|
|
|
let crumb = ValueHistory.Call {f= Model "std::vector::push_back()"; location; in_call= []} in
|
|
|
|
|
if AddressAttributes.is_std_vector_reserved (fst vector) astate then
|
|
|
|
|
(* assume that any call to [push_back] is ok after one called [reserve] on the same vector
|
|
|
|
@ -510,7 +507,7 @@ end
|
|
|
|
|
|
|
|
|
|
module JavaCollection = struct
|
|
|
|
|
let set coll index new_elem : model =
|
|
|
|
|
fun ~caller_summary:_ ~callee_procname:_ location ~ret astate ->
|
|
|
|
|
fun _ ~callee_procname:_ location ~ret astate ->
|
|
|
|
|
let event = ValueHistory.Call {f= Model "Collection.set"; location; in_call= []} in
|
|
|
|
|
let* astate, ((old_addr, old_hist) as old_elem) =
|
|
|
|
|
GenericArrayBackedCollection.element location coll (fst index) astate
|
|
|
|
|