[closures preanalysis] [3/n] Adding models to dispatch functions and remove code for previous specialization and dispatch models

Summary:
This diff finishes the migration from the specialization of methods that take blocks as arguments. Here we delete all the old code and change the way we model dispatch functions so that the tests pass.
- Remove the code for specializing the methods in biabduction.
- Remove the call flags `cf_with_block_parameters` that was only used in this algorithm.
- Removes models for dispatch functions.
- Adds models for dispatch functions as program transformation only in biabduction. To be added in other checkers in the future.

Reviewed By: ngorogiannis

Differential Revision: D23345342

fbshipit-source-id: b5e8542ce
master
Dulma Churchill 4 years ago committed by Facebook GitHub Bot
parent 2e66bf6b8f
commit fdb1640e12

@ -1,32 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block) { block(); }
void dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block) {
block();
}
void dispatch_group_async(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block) {
block();
}
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block) {
block();
}
void dispatch_group_notify(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block) {
block();
}

@ -1,20 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/* We model dispatch_once in a separate file rather than Dispatch.m because this
code doesn't compile together with Foundation. */
#import <Foundation/NSObject.h>
typedef void (^dispatch_block_t)(void);
typedef long dispatch_once_t;
static void _dispatch_once(dispatch_once_t* predicate,
__nonnull dispatch_block_t block) {
block();
}

@ -17,22 +17,17 @@ type t =
; cf_injected_destructor: bool
; cf_interface: bool
; cf_is_objc_block: bool
; cf_virtual: bool
; cf_with_block_parameters: bool }
; cf_virtual: bool }
[@@deriving compare]
let pp f
({ cf_assign_last_arg
; cf_injected_destructor
; cf_interface
; cf_is_objc_block
; cf_with_block_parameters
; cf_virtual }[@warning "+9"]) =
({cf_assign_last_arg; cf_injected_destructor; cf_interface; cf_is_objc_block; cf_virtual}[@warning
"+9"])
=
if cf_assign_last_arg then F.pp_print_string f " assign_last" ;
if cf_injected_destructor then F.pp_print_string f " injected" ;
if cf_interface then F.pp_print_string f " interface" ;
if cf_is_objc_block then F.pp_print_string f " objc_block" ;
if cf_with_block_parameters then F.pp_print_string f " block_params" ;
if cf_virtual then F.pp_print_string f " virtual" ;
()
@ -42,5 +37,4 @@ let default =
; cf_injected_destructor= false
; cf_interface= false
; cf_is_objc_block= false
; cf_with_block_parameters= false
; cf_virtual= false }

@ -18,8 +18,7 @@ type t =
(** true if this is an implicit C++ destructor call injected by the clang frontend *)
; cf_interface: bool
; cf_is_objc_block: bool
; cf_virtual: bool
; cf_with_block_parameters: bool }
; cf_virtual: bool }
[@@deriving compare]
val pp : F.formatter -> t -> unit

@ -178,13 +178,6 @@ let create_normal name stamp = create_with_stamp KNormal name stamp
(** Create a fresh identifier with default name for the given kind. *)
let create_fresh kind = NameGenerator.create_fresh_ident kind (standard_name kind)
let create_fresh_specialized_with_blocks kind =
let fid = create_fresh kind in
(* The stamps are per-procedure unique, add a big enough number to effectively create
a namespace for vars in objc blocks *)
{fid with stamp= fid.stamp + 10000}
let create_none () = create_fresh KNone
(** Generate a footprint identifier with the given name and stamp *)

@ -97,10 +97,6 @@ val update_name_generator : t list -> unit
val create_fresh : kind -> t
(** Create a fresh identifier with default name for the given kind. *)
val create_fresh_specialized_with_blocks : kind -> t
(** Create a fresh identifier with default name for the given kind, with a non-clashing id for objc
block specialization *)
val create_path : string -> t
(** Generate a normal identifier whose name encodes a path given as a string. *)

@ -80,8 +80,6 @@ let append_list t list =
let of_list l = NotReversed (Array.of_list l)
let of_rev_list l = NotReversed (Array.of_list_rev l)
let filter_map t ~f =
let instrs = get_underlying_not_reversed t in
NotReversed (Array.filter_map instrs ~f)

@ -27,8 +27,6 @@ val append_list : not_reversed t -> Sil.instr list -> not_reversed t
val of_list : Sil.instr list -> not_reversed t
val of_rev_list : Sil.instr list -> not_reversed t
val filter_map : not_reversed t -> f:(Sil.instr -> Sil.instr option) -> not_reversed t
val map : not_reversed t -> f:(Sil.instr -> Sil.instr) -> not_reversed t

@ -404,10 +404,6 @@ let as_java_exn ~explanation t =
(* TODO: deprecate this unfortunately named function and use is_clang instead *)
let is_c_method = function ObjC_Cpp _ -> true | _ -> false
let is_c_function = function C _ -> true | _ -> false
let is_clang = function ObjC_Cpp name -> ObjC_Cpp.is_objc_method name | name -> is_c_function name
let is_java_lift f = function Java java_pname -> f java_pname | _ -> false
let is_java_access_method = is_java_lift Java.is_access_method

@ -283,9 +283,6 @@ val is_objc_dealloc : t -> bool
val is_c_method : t -> bool
(** Return true this is an Objective-C/C++ method name. *)
val is_clang : t -> bool
(** Return true if this is a C, C++, or Objective-C procedure name *)
val is_constructor : t -> bool
(** Check if this is a constructor. *)

@ -190,20 +190,5 @@ let pp_instr ~print_types pe0 f instr =
pp_instr_metadata pe0 f metadata )
let add_with_block_parameters_flag instr =
match instr with
| Call (ret_id_typ, Exp.Const (Const.Cfun pname), arg_ts, loc, cf) ->
if
List.exists ~f:(fun (exp, _) -> Exp.is_objc_block_closure exp) arg_ts
&& Procname.is_clang pname
(* to be extended to other methods *)
then
let cf' = {cf with cf_with_block_parameters= true} in
Call (ret_id_typ, Exp.Const (Const.Cfun pname), arg_ts, loc, cf')
else instr
| _ ->
instr
(** Dump an instruction. *)
let d_instr (i : instr) = L.d_pp_with_pe ~color:Pp.Green (pp_instr ~print_types:true) i

@ -78,10 +78,6 @@ val skip_instr : instr
val instr_is_auxiliary : instr -> bool
(** Check if an instruction is auxiliary, or if it comes from source instructions. *)
val add_with_block_parameters_flag : instr -> instr
(** Adds a with_blocks_parameters flag to a method call, when the arguments contain an Objective-C
block, and the method is an Objective-C method (to be extended to other methods) *)
val location_of_instr : instr -> Location.t
(** Get the location of the instruction *)

@ -188,177 +188,3 @@ let with_formals_types ?(has_clang_model = false) callee_pdesc resolved_pname ar
if not (Procname.is_java resolved_pname) then
Attributes.store ~proc_desc:(Some resolved_proc_desc) resolved_attributes ;
resolved_proc_desc
let with_block_args_instrs resolved_pdesc substitutions =
let resolved_pname = Procdesc.get_proc_name resolved_pdesc in
let convert_pvar pvar = Pvar.mk (Pvar.get_name pvar) resolved_pname in
let convert_exp exp =
match exp with
| Exp.Lvar origin_pvar ->
let new_pvar = convert_pvar origin_pvar in
Exp.Lvar new_pvar
| Exp.Lfield (Exp.Lvar origin_pvar, fname, typ) ->
let new_pvar = convert_pvar origin_pvar in
Exp.Lfield (Exp.Lvar new_pvar, fname, typ)
| _ ->
exp
in
let convert_instr (instrs, id_map) instr =
let get_block_name_and_load_captured_vars_instrs block_var loc =
let block_name, extra_formals = Mangled.Map.find block_var substitutions in
let dead_vars, id_exp_typs, load_instrs =
List.map extra_formals ~f:(fun (var, typ) ->
let id = Ident.create_fresh_specialized_with_blocks Ident.knormal in
let pvar = Pvar.mk var resolved_pname in
( Var.of_id id
, (Exp.Var id, pvar, typ, Pvar.ByReference)
, Sil.Load {id; e= Exp.Lvar pvar; root_typ= typ; typ; loc} ) )
|> List.unzip3
in
let remove_temps_instr = Sil.Metadata (ExitScope (dead_vars, loc)) in
(block_name, id_exp_typs, load_instrs, remove_temps_instr)
in
let convert_generic_call return_ids exp origin_args loc call_flags =
let converted_args = List.map ~f:(fun (exp, typ) -> (convert_exp exp, typ)) origin_args in
let call_instr = Sil.Call (return_ids, exp, converted_args, loc, call_flags) in
(call_instr :: instrs, id_map)
in
match instr with
| Sil.Load {id; e= Exp.Lvar block_param as origin_exp; root_typ; typ; loc}
when Mangled.Map.mem (Pvar.get_name block_param) substitutions ->
let id_map = Ident.Map.add id (Pvar.get_name block_param) id_map in
(Sil.Load {id; e= convert_exp origin_exp; root_typ; typ; loc} :: instrs, id_map)
| Sil.Load {id; e= origin_exp; root_typ; typ; loc} ->
(Sil.Load {id; e= convert_exp origin_exp; root_typ; typ; loc} :: instrs, id_map)
| Sil.Store {e1= assignee_exp; root_typ= origin_typ; e2= Exp.Var id; loc}
when Ident.Map.mem id id_map ->
let block_param = Ident.Map.find id id_map in
let block_name, id_exp_typs, load_instrs, remove_temps_instr =
get_block_name_and_load_captured_vars_instrs block_param loc
in
let closure = Exp.Closure {name= block_name; captured_vars= id_exp_typs} in
let instr =
Sil.Store {e1= assignee_exp; root_typ= origin_typ; typ= origin_typ; e2= closure; loc}
in
((remove_temps_instr :: instr :: load_instrs) @ instrs, id_map)
| Sil.Store {e1= assignee_exp; root_typ= origin_typ; e2= origin_exp; loc} ->
let set_instr =
Sil.Store
{ e1= convert_exp assignee_exp
; root_typ= origin_typ
; typ= origin_typ
; e2= convert_exp origin_exp
; loc }
in
(set_instr :: instrs, id_map)
| Sil.Call (return_ids, Exp.Var id, origin_args, loc, call_flags) -> (
try
let block_name, id_exp_typs, load_instrs, remove_temps_instr =
let block_var = Ident.Map.find id id_map in
get_block_name_and_load_captured_vars_instrs block_var loc
in
let call_instr =
let id_exps = List.map ~f:(fun (id, _, typ, _) -> (id, typ)) id_exp_typs in
let converted_args = List.map ~f:(fun (exp, typ) -> (convert_exp exp, typ)) origin_args in
Sil.Call
( return_ids
, Exp.Const (Const.Cfun block_name)
, id_exps @ converted_args
, loc
, call_flags )
in
let instrs = (remove_temps_instr :: call_instr :: load_instrs) @ instrs in
(instrs, id_map)
with Caml.Not_found ->
convert_generic_call return_ids (Exp.Var id) origin_args loc call_flags )
| Sil.Call (return_ids, origin_call_exp, origin_args, loc, call_flags) ->
convert_generic_call return_ids origin_call_exp origin_args loc call_flags
| Sil.Prune (origin_exp, loc, is_true_branch, if_kind) ->
(Sil.Prune (convert_exp origin_exp, loc, is_true_branch, if_kind) :: instrs, id_map)
| Sil.Metadata _ ->
(* these are generated instructions that will be replaced by the preanalysis *)
(instrs, id_map)
in
let f_instr_list instrs =
let rev_instrs, _ = Instrs.fold ~f:convert_instr ~init:([], Ident.Map.empty) instrs in
Instrs.of_rev_list rev_instrs
in
f_instr_list
let append_no_duplicates_formals_and_annot =
Staged.unstage
(IList.append_no_duplicates ~cmp:(fun ((name1, _), _) ((name2, _), _) ->
Mangled.compare name1 name2 ))
let with_block_args callee_pdesc pname_with_block_args block_args =
let callee_attributes = Procdesc.get_attributes callee_pdesc in
(* Substitution from a block parameter to the block name and the new formals
that correspond to the captured variables *)
let substitutions : (Procname.t * (Mangled.t * Typ.t) list) Mangled.Map.t =
List.fold2_exn callee_attributes.formals block_args ~init:Mangled.Map.empty
~f:(fun subts (param_name, _) block_arg_opt ->
match block_arg_opt with
| Some (cl : Exp.closure) ->
let formals_from_captured =
List.map
~f:(fun (_, var, typ, _) ->
(* Here we create fresh names for the new formals, based on the names of the captured
variables annotated with the name of the caller method *)
(Pvar.build_formal_from_pvar var, typ) )
cl.captured_vars
in
Mangled.Map.add param_name (cl.name, formals_from_captured) subts
| None ->
subts )
in
(* Extend formals with fresh variables for the captured variables of the block arguments,
without duplications. *)
let new_formals_blocks_captured_vars, extended_formals_annots =
let new_formals_blocks_captured_vars_with_annots =
let formals_annots =
List.zip_exn callee_attributes.formals callee_attributes.method_annotation.params
in
List.fold formals_annots ~init:[] ~f:(fun acc ((param_name, typ), annot) ->
try
let _, captured = Mangled.Map.find param_name substitutions in
append_no_duplicates_formals_and_annot acc
(List.map captured ~f:(fun captured_var -> (captured_var, Annot.Item.empty)))
with Caml.Not_found ->
append_no_duplicates_formals_and_annot acc [((param_name, typ), annot)] )
in
List.unzip new_formals_blocks_captured_vars_with_annots
in
let translation_unit =
let pname = Procdesc.get_proc_name callee_pdesc in
match Attributes.find_file_capturing_procedure pname with
| Some (source_file, _) ->
source_file
| None ->
Logging.die InternalError
"specialize_with_block_args ahould only be called with defined procedures, but we cannot \
find the captured file of procname %a"
Procname.pp pname
in
let resolved_attributes =
{ callee_attributes with
proc_name= pname_with_block_args
; is_defined= true
; formals= new_formals_blocks_captured_vars
; method_annotation=
{return= callee_attributes.method_annotation.return; params= extended_formals_annots}
; translation_unit }
in
let resolved_pdesc = Procdesc.from_proc_attributes resolved_attributes in
Logging.(debug Analysis Verbose)
"signature of base method %a@." Procdesc.pp_signature callee_pdesc ;
Logging.(debug Analysis Verbose)
"signature of specialized method %a@." Procdesc.pp_signature resolved_pdesc ;
let proc_desc =
convert_cfg ~callee_pdesc ~resolved_pdesc
~f_instr_list:(with_block_args_instrs resolved_pdesc substitutions)
in
Attributes.store ~proc_desc:(Some proc_desc) resolved_attributes ;
proc_desc

@ -15,11 +15,3 @@ val with_formals_types :
typ) where name is a parameter. The resulting procdesc is isomorphic but all the type of the
parameters are replaced in the instructions according to the list. The virtual calls are also
replaced to match the parameter types *)
val with_block_args : Procdesc.t -> Procname.t -> Exp.closure option list -> Procdesc.t
(** Creates a copy of a procedure description given a list of possible closures that are passed as
arguments to the method. The resulting procdesc is isomorphic but
- the block parameters are replaces with the closures
- the parameters of the method are extended with parameters for the captured variables in the
closures *)

@ -0,0 +1,18 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
let dispatch_models =
[ "_dispatch_once"
; "dispatch_async"
; "dispatch_after"
; "dispatch_group_async"
; "dispatch_barrier_async"
; "dispatch_group_notify" ]
let is_model proc_name = List.mem dispatch_models ~equal:String.equal (Procname.to_string proc_name)

@ -0,0 +1,10 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
val is_model : Procname.t -> bool

@ -1065,6 +1065,11 @@ let declare_locals_and_ret tenv pdesc (prop_ : Prop.normal Prop.t) =
prop'
let get_closure_opt actual_params =
List.find_map actual_params ~f:(fun (exp, _) ->
match exp with Exp.Closure c when Procname.is_objc_block c.name -> Some c | _ -> None )
(** Execute [instr] with a symbolic heap [prop].*)
let rec sym_exec
( {InterproceduralAnalysis.proc_desc= current_pdesc; analyze_dependency; err_log; tenv} as
@ -1091,6 +1096,15 @@ let rec sym_exec
let proc_exp' = Prop.exp_normalize_prop tenv prop_ proc_exp in
let par' = List.map ~f:(fun (id_exp, _, typ, _) -> (id_exp, typ)) c.captured_vars in
Sil.Call (ret, proc_exp', par' @ par, loc, call_flags)
| Exp.Const (Const.Cfun callee_pname) when ObjCDispatchModels.is_model callee_pname -> (
match get_closure_opt par with
| Some c ->
(* We assume that for these modelled functions, the block passed as parameter doesn't
have arguments, so we only pass the captured variables. *)
let args = List.map ~f:(fun (id_exp, _, typ, _) -> (id_exp, typ)) c.captured_vars in
Sil.Call (ret, Exp.Const (Const.Cfun c.name), args, loc, call_flags)
| None ->
Sil.Call (ret, exp', par, loc, call_flags) )
| _ ->
Sil.Call (ret, exp', par, loc, call_flags)
in
@ -1189,29 +1203,11 @@ let rec sym_exec
exec_skip_call ~reason ret_annots proc_attrs.ProcAttributes.ret_type )
in
List.fold ~f:(fun acc pname -> exec_one_pname pname @ acc) ~init:[] resolved_pnames
| _ -> (
| _ ->
(* Generic fun call with known name *)
let prop_r, n_actual_params = normalize_params analysis_data prop_ actual_params in
(* method with block parameters *)
let with_block_parameters_summary_opt =
if call_flags.CallFlags.cf_with_block_parameters then
SymExecBlocks.resolve_method_with_block_args_and_analyze analysis_data callee_pname
actual_params
else None
in
match with_block_parameters_summary_opt with
| Some (resolved_summary, extended_actual_params) ->
let prop_r, n_extended_actual_params =
normalize_params analysis_data prop_r extended_actual_params
in
Logging.d_strln "Calling method specialized with blocks... " ;
proc_call resolved_summary
(call_args prop_r callee_pname n_extended_actual_params ret_id_typ loc)
| None ->
(* Generic fun call with known name *)
let resolve_and_analyze_result =
resolve_and_analyze_clang analysis_data prop_r n_actual_params callee_pname
call_flags
resolve_and_analyze_clang analysis_data prop_r n_actual_params callee_pname call_flags
in
let resolved_pname = resolve_and_analyze_result.resolved_pname in
let resolved_pdesc_opt = resolve_and_analyze_result.resolved_procdesc_opt in
@ -1239,8 +1235,7 @@ let rec sym_exec
let ret_annots =
match resolved_summary_opt with
| Some (proc_desc, _) ->
(Procdesc.get_attributes proc_desc).ProcAttributes.method_annotation
.return
(Procdesc.get_attributes proc_desc).ProcAttributes.method_annotation.return
| None ->
load_ret_annots resolved_pname
in
@ -1252,8 +1247,8 @@ let rec sym_exec
ClangMethodKind.equal attrs.ProcAttributes.clang_method_kind
ClangMethodKind.OBJC_INSTANCE
in
skip_call ~is_objc_instance_method ~reason prop path resolved_pname
ret_annots loc ret_id_typ ret_type n_actual_params
skip_call ~is_objc_instance_method ~reason prop path resolved_pname ret_annots
loc ret_id_typ ret_type n_actual_params
| None ->
skip_call ~reason prop path resolved_pname ret_annots loc ret_id_typ
(snd ret_id_typ) n_actual_params )
@ -1262,7 +1257,7 @@ let rec sym_exec
(Option.value_exn resolved_summary_opt)
(call_args prop resolved_pname n_actual_params ret_id_typ loc)
in
List.concat_map ~f:do_call sentinel_result ) ) )
List.concat_map ~f:do_call sentinel_result ) )
| Sil.Call (ret_id_typ, fun_exp, actual_params, loc, call_flags) ->
(* Call via function pointer *)
let prop_r, n_actual_params = normalize_params analysis_data prop_ actual_params in

@ -1,101 +0,0 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
(* Given two lists of tuples (exp1, var1, typ1) and (exp2, var2, typ2) append the lists avoiding
duplicates, where if the variables exist we check their equality, otherwise we check the equality
of the expressions. This is to avoid adding the same captured variable twice. *)
let append_no_duplicates_vars =
let cmp (exp1, var1_opt, _) (exp2, var2_opt, _) =
match (var1_opt, var2_opt) with
| Some var1, Some var2 ->
Pvar.compare var1 var2
| None, None ->
Exp.compare exp1 exp2
| Some _, None ->
1
| None, Some _ ->
-1
in
Staged.unstage (IList.append_no_duplicates ~cmp)
(* Given a list of actual parameters for a function, replaces the closures with the
captured variables, avoiding adding the same captured variable twice. *)
let get_extended_args_for_method_with_block_analysis act_params =
let ext_actuals = List.map ~f:(fun (exp, typ) -> (exp, None, typ)) act_params in
let args_and_captured =
List.fold ext_actuals ~init:[] ~f:(fun all_args act_param ->
match act_param with
| Exp.Closure cl, _, _ ->
let captured =
List.map ~f:(fun (exp, var, typ, _) -> (exp, Some var, typ)) cl.captured_vars
in
append_no_duplicates_vars all_args captured
| _ ->
List.append all_args [act_param] )
in
List.map ~f:(fun (exp, _, typ) -> (exp, typ)) args_and_captured
let resolve_method_with_block_args_and_analyze
{InterproceduralAnalysis.analyze_dependency; analyze_pdesc_dependency} pname act_params =
let pdesc_opt =
match analyze_dependency pname with
| Some (proc_desc, _) ->
Some proc_desc
| None ->
AnalysisCallbacks.get_proc_desc pname
in
match pdesc_opt with
| Some pdesc
when Procdesc.is_defined pdesc
&& Int.equal (List.length (Procdesc.get_formals pdesc)) (List.length act_params)
(* only specialize defined methods, and when formals and actuals have the same length *)
-> (
(* a list with the same length of the actual params of the function,
containing either a Closure or None. *)
let block_args =
List.map act_params ~f:(function
| Exp.Closure cl, _ when Procname.is_objc_block cl.name ->
Some cl
| _ ->
None )
in
(* name for the specialized method instantiated with block arguments *)
let pname_with_block_args =
let block_name_args =
List.filter_map block_args ~f:(function
| Some (cl : Exp.closure) ->
Some (Procname.block_name_of_procname cl.name)
| None ->
None )
in
Procname.with_block_parameters pname block_name_args
in
(* new procdesc cloned from the original one, where the block parameters have been
replaced by the block arguments. The formals have also been expanded with the captured variables *)
let specialized_pdesc =
SpecializeProcdesc.with_block_args pdesc pname_with_block_args block_args
in
Logging.(debug Analysis Verbose) "Instructions of specialized method:@." ;
Procdesc.iter_instrs
(fun _ instr ->
Logging.(debug Analysis Verbose) "%a@." (Sil.pp_instr ~print_types:false Pp.text) instr )
specialized_pdesc ;
Logging.(debug Analysis Verbose) "End of instructions@." ;
match analyze_pdesc_dependency specialized_pdesc with
| Some summary ->
(* Since the closures in the formals were replaced by the captured variables,
we do the same with the actual arguments *)
let extended_args = get_extended_args_for_method_with_block_analysis act_params in
Some ((specialized_pdesc, summary), extended_args)
| None ->
None )
| _ ->
None

@ -1,20 +0,0 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
val resolve_method_with_block_args_and_analyze :
BiabductionSummary.t InterproceduralAnalysis.t
-> Procname.t
-> (Exp.t * Typ.t) list
-> ((Procdesc.t * BiabductionSummary.t) * (Exp.t * Typ.t) list) option
(** [resolve_method_with_block_args_and_analyze caller_pdesc pname args] create a copy of the method
pname if it is defined and it's called with the correct number of arguments, and some arguments
are block closures. The copy is created by adding extra formals for each captured variable, and
by swapping the calls to the block arguments to the calls to the concrete blocks. The new
procedure is analyzed and the possibly computed summary is returned together with the list of
arguments where the closures where swapped by their captured variables. *)

@ -124,6 +124,11 @@ let is_initializer proc_desc =
Procname.is_constructor proc_name
let is_dispatch_model proc_desc =
let proc_name = Procdesc.get_proc_name proc_desc in
ObjCDispatchModels.is_model proc_name
let replace_with_specialize_methods cfg _node instr =
match instr with
| Sil.Call (ret, Exp.Const (Const.Cfun callee_pname), actual_params, loc, flags)
@ -133,7 +138,10 @@ let replace_with_specialize_methods cfg _node instr =
parameter and then run the block. It doesn't work well when the block is instead stored in
a field. This case will be left as future work, and we won't specialize common cases where this
happens such as setters or initializers. *)
| Some proc_desc when (not (is_objc_setter proc_desc)) && not (is_initializer proc_desc) -> (
| Some proc_desc
when (not (is_objc_setter proc_desc))
&& (not (is_initializer proc_desc))
&& not (is_dispatch_model proc_desc) -> (
let callee_attributes = Procdesc.get_attributes proc_desc in
match
formals_actuals_map callee_attributes.formals callee_attributes.method_annotation.params

@ -291,9 +291,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
let call_instr =
Sil.Call (ret_id', function_sil, params @ forwarded_params, sil_loc, call_flags)
in
let call_instr' = Sil.add_with_block_parameters_flag call_instr in
mk_trans_result ret_exps
{empty_control with instrs= forwarded_init_instrs @ [call_instr']; initd_exps}
{empty_control with instrs= forwarded_init_instrs @ [call_instr]; initd_exps}
(** Given a captured var, return the instruction to assign it to a temp *)

@ -1,5 +1,5 @@
build_systems/codetoanalyze/objc_getters_setters/B.m, B.calling_c_function_with_block_parameters_sets_fields_correctly, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure calling_c_function_with_block_parameters_sets_fields_correctly,start of procedure calling_c_function_with_block_parameters,start of procedure c_function(),start of procedure block,return from a call to objc_blockB.calling_c_function_with_block_parameters_3,start of procedure block,return from a call to objc_blockB.calling_c_function_with_block_parameters_4,return from a call to c_function_objc_blockB.calling_c_function_with_block_parameters_3_objc_blockB.calling_c_function_with_block_parameters_4,return from a call to B.calling_c_function_with_block_parameters,Taking true branch]
build_systems/codetoanalyze/objc_getters_setters/B.m, B.calling_method_with_block_parameters_sets_fields_correctly, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure calling_method_with_block_parameters_sets_fields_correctly,start of procedure calling_method_with_block_parameters,start of procedure foo:and:and_also:and:,start of procedure block,return from a call to objc_blockB.calling_method_with_block_parameters_1,start of procedure block,return from a call to objc_blockB.calling_method_with_block_parameters_2,return from a call to A.foo:and:and_also:and:_objc_blockB.calling_method_with_block_parameters_1_objc_blockB.calling_method_with_block_parameters_2,return from a call to B.calling_method_with_block_parameters,Taking true branch]
build_systems/codetoanalyze/objc_getters_setters/B.m, B.calling_c_function_with_block_parameters_sets_fields_correctly, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure calling_c_function_with_block_parameters_sets_fields_correctly,start of procedure calling_c_function_with_block_parameters,start of procedure c_function(),start of procedure block,return from a call to objc_blockB.calling_c_function_with_block_parameters_3,start of procedure block,return from a call to objc_blockB.calling_c_function_with_block_parameters_4,return from a call to c_function,return from a call to B.calling_c_function_with_block_parameters,Taking true branch]
build_systems/codetoanalyze/objc_getters_setters/B.m, B.calling_method_with_block_parameters_sets_fields_correctly, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure calling_method_with_block_parameters_sets_fields_correctly,start of procedure calling_method_with_block_parameters,start of procedure foo:and:and_also:and:,start of procedure block,return from a call to objc_blockB.calling_method_with_block_parameters_1,start of procedure block,return from a call to objc_blockB.calling_method_with_block_parameters_2,return from a call to A.foo:and:and_also:and:,return from a call to B.calling_method_with_block_parameters,Taking true branch]
build_systems/codetoanalyze/objc_getters_setters/B.m, B.npe_no_bad_footprint_in_getter:, 3, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure npe_no_bad_footprint_in_getter:,start of procedure metadata,return from a call to A.metadata]
build_systems/codetoanalyze/objc_getters_setters/B.m, B.npe_no_bad_footprint_in_setter:andMetadata:, 3, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure npe_no_bad_footprint_in_setter:andMetadata:,start of procedure setMetadata:,return from a call to A.setMetadata:]
build_systems/codetoanalyze/objc_getters_setters/B.m, B.npe_no_precondition_not_met:, 4, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure npe_no_precondition_not_met:,start of procedure infer_field_get_spec:,start of procedure withMetadata:,return from a call to A.withMetadata:,return from a call to B.infer_field_get_spec:,start of procedure getX,return from a call to A.getX,Taking true branch]

@ -3,8 +3,8 @@ codetoanalyze/objc/biabduction/field_superclass/field.c, field_superclass_main,
codetoanalyze/objc/biabduction/global_const/global_const.m, SimpleRoot.doSomethingBadWithDict:andString:, 3, NULL_DEREFERENCE, B2, ERROR, [start of procedure doSomethingBadWithDict:andString:,Message stringByAppendingString: with receiver nil returns nil.]
codetoanalyze/objc/biabduction/global_const/global_const.m, SimpleRoot.doSomethingOkWithDict:andString:, 3, NULL_DEREFERENCE, B2, ERROR, [start of procedure doSomethingOkWithDict:andString:,Message stringByAppendingString: with receiver nil returns nil.]
codetoanalyze/objc/biabduction/initialization/compound_literal.c, init_with_compound_literal, 2, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure init_with_compound_literal()]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleStaticVar.m, RetainCSV.foo, 13, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure foo,start of procedure setHandler:,return from a call to RetainCSV.setHandler:_objc_blockRetainCSV.foo_1]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleStaticVar.m, RetainCSV.foo, 13, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure foo,start of procedure setHandler:,return from a call to RetainCSV.setHandler:_objc_blockRetainCSV.foo_1]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleStaticVar.m, RetainCSV.foo, 13, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure foo,start of procedure block,start of procedure init,return from a call to RetainCSV.init,return from a call to objc_blockRetainCSV.foo_3,start of procedure block,start of procedure init,return from a call to RetainCSV.init,return from a call to objc_blockRetainCSV.foo_2,start of procedure setHandler:,return from a call to RetainCSV.setHandler:]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleStaticVar.m, RetainCSV.foo, 13, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure foo,start of procedure block,start of procedure init,return from a call to RetainCSV.init,return from a call to objc_blockRetainCSV.foo_3,start of procedure block,start of procedure init,return from a call to RetainCSV.init,return from a call to objc_blockRetainCSV.foo_2,start of procedure setHandler:,return from a call to RetainCSV.setHandler:]
codetoanalyze/objc/biabduction/npe/null_returned_by_method.m, NullReturnedByMethodA.test1, 1, NULL_DEREFERENCE, B5, ERROR, [start of procedure test1,start of procedure test,return from a call to NullReturnedByMethodA.test]
codetoanalyze/objc/biabduction/procdescs/main.c, ProcdescMain, 3, BIABDUCTION_MEMORY_LEAK, no_bucket, ERROR, [start of procedure ProcdescMain(),Skipping plusX:andY:: method has no implementation]
codetoanalyze/objc/biabduction/procdescs/main.c, call_nslog, 3, BIABDUCTION_MEMORY_LEAK, no_bucket, ERROR, [start of procedure call_nslog(),Skipping NSLog(): method has no implementation]
@ -23,18 +23,18 @@ codetoanalyze/objc/shared/block/block.m, main1, 30, DIVIDE_BY_ZERO, no_bucket, E
codetoanalyze/objc/shared/block/block_no_args.m, Block_no_args.m, 10, NULL_DEREFERENCE, B1, ERROR, [start of procedure m,start of procedure block,return from a call to objc_blockBlock_no_args.m_1,Taking true branch]
codetoanalyze/objc/shared/category_procdesc/main.c, CategoryProcdescMain, 3, BIABDUCTION_MEMORY_LEAK, no_bucket, ERROR, [start of procedure CategoryProcdescMain(),Skipping performDaysWork: method has no implementation]
codetoanalyze/objc/shared/field_superclass/SuperExample.m, ASuper.init, 2, NULL_DEREFERENCE, B2, ERROR, [start of procedure init]
codetoanalyze/objc/biabduction/blocks_in_heap/BlockInHeap.m, block_in_heap_executed_after_bi_abduction_ok_test, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure block_in_heap_executed_after_bi_abduction_ok_test(),start of procedure block_in_heap_executed_after_bi_abduction_ok_no_retain_cycle(),start of procedure assign_block_to_ivar,start of procedure setHandler:,return from a call to BlockInHeap.setHandler:_objc_blockBlockInHeap.assign_block_to_ivar_1,return from a call to BlockInHeap.assign_block_to_ivar,start of procedure handler,return from a call to BlockInHeap.handler,start of procedure block,return from a call to objc_blockBlockInHeap.assign_block_to_ivar_1,return from a call to block_in_heap_executed_after_bi_abduction_ok_no_retain_cycle,Taking true branch]
codetoanalyze/objc/biabduction/blocks_in_heap/BlockInHeap.m, block_in_heap_executed_after_bi_abduction_ok_test, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure block_in_heap_executed_after_bi_abduction_ok_test(),start of procedure block_in_heap_executed_after_bi_abduction_ok_no_retain_cycle(),start of procedure assign_block_to_ivar,start of procedure setHandler:,return from a call to BlockInHeap.setHandler:,return from a call to BlockInHeap.assign_block_to_ivar,start of procedure handler,return from a call to BlockInHeap.handler,start of procedure block,return from a call to objc_blockBlockInHeap.assign_block_to_ivar_1,return from a call to block_in_heap_executed_after_bi_abduction_ok_no_retain_cycle,Taking true branch]
codetoanalyze/objc/biabduction/field_superclass/SubtypingExample.m, Employee.initWithName:andAge:andEducation:, 6, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure initWithName:andAge:andEducation:,start of procedure initWithName:andAge:,return from a call to Person.initWithName:andAge:,Taking true branch]
codetoanalyze/objc/biabduction/field_superclass/SubtypingExample.m, subtyping_test, 0, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure subtyping_test(),start of procedure testFields(),start of procedure setEmployeeEducation:,return from a call to Employee.setEmployeeEducation:,start of procedure setAge:,return from a call to Person.setAge:,start of procedure setEmployeeEducation:,return from a call to Employee.setEmployeeEducation:,start of procedure getAge,return from a call to Person.getAge,return from a call to testFields]
codetoanalyze/objc/biabduction/initialization/struct_initlistexpr.c, field_set_correctly, 2, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure field_set_correctly()]
codetoanalyze/objc/biabduction/initialization/struct_initlistexpr.c, implicit_expr_set_correctly, 3, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure implicit_expr_set_correctly()]
codetoanalyze/objc/biabduction/initialization/struct_initlistexpr.c, point_coords_set_correctly, 2, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure point_coords_set_correctly()]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockAsParameter.m, FBSomeDataManager.fetchNewData, 2, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure fetchNewData,start of procedure initWithCompletionBlock:,return from a call to Fetcher.initWithCompletionBlock:_objc_blockFBSomeDataManager.fetchNewData_1]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockAsParameter.m, FBSomeDataManager.fetchNewData, 2, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure fetchNewData,start of procedure initWithCompletionBlock:,return from a call to Fetcher.initWithCompletionBlock:_objc_blockFBSomeDataManager.fetchNewData_1]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockCapturedVar.m, LinkResolver.test_bad, 3, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure test_bad,start of procedure setDidFinishLoad:,return from a call to Listener.setDidFinishLoad:_objc_blockLinkResolver.test_bad_1]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockCapturedVar.m, LinkResolver.test_bad, 3, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure test_bad,start of procedure setDidFinishLoad:,return from a call to Listener.setDidFinishLoad:_objc_blockLinkResolver.test_bad_1]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, RCBlock.retain_self_in_block, 1, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure retain_self_in_block,start of procedure setHandler:,return from a call to RCBlock.setHandler:_objc_blockRCBlock.retain_self_in_block_1]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, RCBlock.retain_self_in_block, 1, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure retain_self_in_block,start of procedure setHandler:,return from a call to RCBlock.setHandler:_objc_blockRCBlock.retain_self_in_block_1]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockAsParameter.m, FBSomeDataManager.fetchNewData, 2, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure fetchNewData,start of procedure initWithCompletionBlock:,return from a call to Fetcher.initWithCompletionBlock:]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockAsParameter.m, FBSomeDataManager.fetchNewData, 2, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure fetchNewData,start of procedure initWithCompletionBlock:,return from a call to Fetcher.initWithCompletionBlock:]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockCapturedVar.m, LinkResolver.test_bad, 3, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure test_bad,start of procedure setDidFinishLoad:,return from a call to Listener.setDidFinishLoad:]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlockCapturedVar.m, LinkResolver.test_bad, 3, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure test_bad,start of procedure setDidFinishLoad:,return from a call to Listener.setDidFinishLoad:]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, RCBlock.retain_self_in_block, 1, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure retain_self_in_block,start of procedure setHandler:,return from a call to RCBlock.setHandler:]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, RCBlock.retain_self_in_block, 1, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure retain_self_in_block,start of procedure setHandler:,return from a call to RCBlock.setHandler:]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, objc_blockretain_a_in_block_cycle_3, 1, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure block,start of procedure setChild:,return from a call to RCBlockAA.setChild:]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, objc_blockretain_a_in_block_cycle_3, 1, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure block,start of procedure setChild:,return from a call to RCBlockAA.setChild:]
codetoanalyze/objc/biabduction/memory_leaks_benchmark/RetainCycleBlocks.m, retain_a_in_block_cycle, 4, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure retain_a_in_block_cycle(),start of procedure setB:,return from a call to RCBlockAA.setB:,start of procedure setA:,return from a call to RCBlock.setA:]
@ -99,7 +99,7 @@ codetoanalyze/objc/biabduction/npe/dynamic_dispatch.m, objc_blockDynamicDispatch
codetoanalyze/objc/biabduction/npe/ivar_blocks.m, MyClass.ivar_npe, 1, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure ivar_npe]
codetoanalyze/objc/biabduction/npe/skip_method_with_nil_object.m, SkipMethodNilA.testBug:, 6, PARAMETER_NOT_NULL_CHECKED, B2, WARNING, [start of procedure testBug:,Message get_a with receiver nil returns nil.,Message skip_method with receiver nil returns nil.,Taking false branch]
codetoanalyze/objc/biabduction/property/main.c, property_main, 3, BIABDUCTION_MEMORY_LEAK, no_bucket, ERROR, [start of procedure property_main(),Skipping aProperty: method has no implementation]
codetoanalyze/objc/biabduction/resource_leaks/Dispatch_sources.m, ProcessContentsOfFile, 35, RESOURCE_LEAK, no_bucket, ERROR, [start of procedure ProcessContentsOfFile(),Taking false branch,Skipping dispatch_get_global_queue(): method has no implementation,Skipping dispatch_source_create(): method has no implementation,Taking false branch,Skipping dispatch_source_set_event_handler(): method has no implementation,Skipping dispatch_source_set_cancel_handler(): method has no implementation]
codetoanalyze/objc/biabduction/resource_leaks/Dispatch_sources.m, ProcessContentsOfFile, 35, RESOURCE_LEAK, no_bucket, ERROR, [start of procedure ProcessContentsOfFile(),Taking false branch,Skipping dispatch_get_global_queue(): method has no implementation,Skipping dispatch_source_create(): method has no implementation,Taking false branch]
codetoanalyze/objc/biabduction/resource_leaks/Dispatch_sources.m, objc_blockProcessContentsOfFile_2, 6, BIABDUCTION_MEMORY_LEAK, no_bucket, ERROR, [start of procedure block,Skipping dispatch_source_get_data(): method has no implementation,Taking true branch,Skipping MyProcessFileData(): method has no implementation]
codetoanalyze/objc/biabduction/resource_leaks/ResourceLeakExample.m, NSFileHandle.fileHandleForLoggingAtPath:mode:, 9, RESOURCE_LEAK, no_bucket, ERROR, [start of procedure fileHandleForLoggingAtPath:mode:,Taking true branch,Skipping fileSystemRepresentation: method has no implementation,Taking false branch,Taking true branch,Skipping autorelease: no implementation found for method declared in Objective-C protocol]
codetoanalyze/objc/shared/annotations/nonnull_annotations.m, NonnullAnnot.test1:, 2, PARAMETER_NOT_NULL_CHECKED, B2, WARNING, [start of procedure test1:,Message child with receiver nil returns nil.]
@ -107,5 +107,5 @@ codetoanalyze/objc/shared/annotations/nonnull_annotations.m, NonnullAnnot.test3:
codetoanalyze/objc/shared/annotations/nullable_annotations.m, User.otherUserName, 2, NULL_DEREFERENCE, B2, ERROR, [start of procedure otherUserName,Skipping otherUser: method has no implementation]
codetoanalyze/objc/shared/annotations/nullable_annotations.m, npe_property_nullable, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure npe_property_nullable(),Skipping child: method has no implementation]
codetoanalyze/objc/shared/annotations/nullable_annotations_fields.m, A.nullable_field, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure nullable_field,Skipping getA(): method has no implementation]
codetoanalyze/objc/shared/block/dispatch.m, DispatchA.dispatch_a_block_variable_from_macro_delivers_initialised_object, 3, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure dispatch_a_block_variable_from_macro_delivers_initialised_object,start of procedure dispatch_a_block_variable_from_macro,return from a call to DispatchA.dispatch_a_block_variable_from_macro]
codetoanalyze/objc/shared/block/dispatch.m, DispatchA.dispatch_a_block_variable_from_macro_delivers_initialised_object, 3, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure dispatch_a_block_variable_from_macro_delivers_initialised_object,start of procedure dispatch_a_block_variable_from_macro,Skipping _dispatch_once(): method has no implementation,return from a call to DispatchA.dispatch_a_block_variable_from_macro]
codetoanalyze/objc/shared/npe/Available_expr.m, Available_expr.test_no_bug, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure test_no_bug,Taking true branch]

@ -52,7 +52,7 @@ digraph cfg {
"capture#A#instance.d411336575e4bf632a1828f5f5979726_2" [label="2: Exit A.capture \n " color=yellow style=filled]
"capture#A#instance.d411336575e4bf632a1828f5f5979726_3" [label="3: Message Call: sHandler: \n n$3=*&self:A* [line 45, column 4]\n n$4=*n$3._b:B* [line 45, column 4]\n n$0=*&self:A* [line 45, column 16]\n n$5=_fun_B.sHandler:[objc_blockA.capture_1](n$0:A*,n$4:B*) block_params virtual [line 45, column 3]\n " shape="box"]
"capture#A#instance.d411336575e4bf632a1828f5f5979726_3" [label="3: Message Call: sHandler: \n n$3=*&self:A* [line 45, column 4]\n n$4=*n$3._b:B* [line 45, column 4]\n n$0=*&self:A* [line 45, column 16]\n n$5=_fun_B.sHandler:[objc_blockA.capture_1](n$0:A*,n$4:B*) virtual [line 45, column 3]\n " shape="box"]
"capture#A#instance.d411336575e4bf632a1828f5f5979726_3" -> "capture#A#instance.d411336575e4bf632a1828f5f5979726_2" ;

@ -77,7 +77,7 @@ digraph cfg {
"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_3" -> "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_2" ;
"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" [label="4: Call _fun_foo \n n$14=*&self:A* [line 40, column 7]\n n$16=*&self:A* [line 43, column 7]\n n$18=*&self:A* [line 46, column 7]\n n$19=_fun_foo[objc_blockA.bar2_3^objc_blockA.bar2_4](n$14:A*,n$18:A*) block_params [line 39, column 3]\n " shape="box"]
"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" [label="4: Call _fun_foo \n n$14=*&self:A* [line 40, column 7]\n n$16=*&self:A* [line 43, column 7]\n n$18=*&self:A* [line 46, column 7]\n n$19=_fun_foo[objc_blockA.bar2_3^objc_blockA.bar2_4](n$14:A*,n$18:A*) [line 39, column 3]\n " shape="box"]
"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" -> "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_3" ;
@ -96,7 +96,7 @@ digraph cfg {
"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_4" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_3" ;
"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" [label="5: Call _fun_foo \n n$3=*&self:A* [line 27, column 7]\n n$4=*&x:int [line 27, column 7]\n n$7=*&self:A* [line 30, column 7]\n n$10=*&a:A* [line 33, column 7]\n n$11=_fun_foo[objc_blockA.bar:_1^objc_blockA.bar:_2](n$4:int,n$3:A*,n$10:A*) block_params [line 26, column 3]\n " shape="box"]
"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" [label="5: Call _fun_foo \n n$3=*&self:A* [line 27, column 7]\n n$4=*&x:int [line 27, column 7]\n n$7=*&self:A* [line 30, column 7]\n n$10=*&a:A* [line 33, column 7]\n n$11=_fun_foo[objc_blockA.bar:_1^objc_blockA.bar:_2](n$4:int,n$3:A*,n$10:A*) [line 26, column 3]\n " shape="box"]
"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_4" ;

@ -118,6 +118,9 @@ id nsarray_first_object_constant(NSArray* array) { return array.firstObject; }
id nsarray_last_object_constant(NSArray* array) { return array.lastObject; }
// find element
// To be uncommented when we find a solution to avoiding absolute paths
// from the standard library in tests.
/*
NSInteger nsarray_binary_search_log_FN(NSArray* sorted_array) {
NSNumber* target = @5;
return [sorted_array indexOfObject:target
@ -127,6 +130,7 @@ NSInteger nsarray_binary_search_log_FN(NSArray* sorted_array) {
return [lhs compare:rhs];
}];
}
*/
// sort array

@ -33,7 +33,7 @@ void doBlockA_linear_FN(int a) {
runBlockA(block);
}
void doBlockA_direct_block_linear_FN(int a) {
void doBlockA_direct_block_linear(int a) {
runBlockA(^{
loop_linear(a);
});

@ -3,7 +3,6 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_access_linear, 3 + 7 ⋅ array
codetoanalyze/objc/performance/NSArray.m, nsarray_add_object_constant, 8, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_add_objects_from_array_linear_FN, 8, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_array_with_objects_constant, 27, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_binary_search_log_FN, 10, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_contains_object_linear, 3 + array->elements.length.ub, OnUIThread:false, [{array->elements.length.ub},Modeled call to NSArray.containsObject:]
codetoanalyze/objc/performance/NSArray.m, nsarray_count_bounded_linear, 3 + 3 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_empty_array_constant, 8, OnUIThread:false, []
@ -24,7 +23,6 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_next_object_linear, 5 + array-
codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant, 34, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_constant, 39, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_nlogn, 9 + array->elements.length.ub × log(array->elements.length.ub), OnUIThread:false, [{array->elements.length.ub},Modeled call to NSArray.sortedArrayUsingDescriptors:,{array->elements.length.ub},Modeled call to NSArray.sortedArrayUsingDescriptors:]
codetoanalyze/objc/performance/NSArray.m, objc_blocknsarray_binary_search_log_FN_1, 5, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear1, 3 + 3 ⋅ dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear2, 6 + 3 ⋅ dict->elements.length.ub + 3 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear, 3 + 3 ⋅ dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop]
@ -80,13 +78,14 @@ codetoanalyze/objc/performance/araii.m, Araii.initWithBuffer, 15, OnUIThread:fa
codetoanalyze/objc/performance/araii.m, Araii.setBuffer:, 4, OnUIThread:false, []
codetoanalyze/objc/performance/araii.m, memory_leak_raii_main, 18, OnUIThread:false, []
codetoanalyze/objc/performance/block.m, block_multiply_array_linear, 13 + 5 ⋅ array->elements.length.ub + 4 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Call to objc_blockblock_multiply_array_linear_1,Loop,{array->elements.length.ub},Call to objc_blockblock_multiply_array_linear_1,Loop]
codetoanalyze/objc/performance/block.m, doBlockA_direct_block_linear_FN, 5, OnUIThread:false, []
codetoanalyze/objc/performance/block.m, doBlockA_direct_block_linear, 10 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to runBlockA[objc_blockdoBlockA_direct_block_linear_3],Call to objc_blockdoBlockA_direct_block_linear_3,Call to loop_linear,Loop,{a},Call to runBlockA[objc_blockdoBlockA_direct_block_linear_3],Call to objc_blockdoBlockA_direct_block_linear_3,Call to loop_linear,Loop]
codetoanalyze/objc/performance/block.m, doBlockA_linear_FN, 7, OnUIThread:false, []
codetoanalyze/objc/performance/block.m, loop_linear, 3 + 3 ⋅ x + 2 ⋅ (1+max(0, x)), OnUIThread:false, [{1+max(0, x)},Loop,{x},Loop]
codetoanalyze/objc/performance/block.m, objc_blockblock_multiply_array_linear_1, 8 + 5 ⋅ array->elements.length.ub + 4 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/block.m, objc_blockdoBlockA_direct_block_linear_FN_3, 5 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to loop_linear,Loop,{a},Call to loop_linear,Loop]
codetoanalyze/objc/performance/block.m, objc_blockdoBlockA_direct_block_linear_3, 5 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to loop_linear,Loop,{a},Call to loop_linear,Loop]
codetoanalyze/objc/performance/block.m, objc_blockdoBlockA_linear_FN_2, 5 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to loop_linear,Loop,{a},Call to loop_linear,Loop]
codetoanalyze/objc/performance/block.m, runBlockA, 3, OnUIThread:false, []
codetoanalyze/objc/performance/block.m, runBlockA[objc_blockdoBlockA_direct_block_linear_3], 8 + 3 ⋅ a[doBlockA_direct_block_linear()] + 2 ⋅ (1+max(0, a[doBlockA_direct_block_linear()])), OnUIThread:false, [{1+max(0, a[doBlockA_direct_block_linear()])},Call to objc_blockdoBlockA_direct_block_linear_3,Call to loop_linear,Loop,{a[doBlockA_direct_block_linear()]},Call to objc_blockdoBlockA_direct_block_linear_3,Call to loop_linear,Loop]
codetoanalyze/objc/performance/break.m, break_constant_FP, 8 + 5 ⋅ p + 2 ⋅ (1+max(0, p)), OnUIThread:false, [{1+max(0, p)},Call to break_loop,Loop,{p},Call to break_loop,Loop]
codetoanalyze/objc/performance/break.m, break_loop, 5 + 5 ⋅ p + 2 ⋅ (1+max(0, p)), OnUIThread:false, [{1+max(0, p)},Loop,{p},Loop]
codetoanalyze/objc/performance/break.m, break_loop_with_t, 7 + 5 ⋅ p + 2 ⋅ (1+max(0, p)), OnUIThread:false, [{1+max(0, p)},Loop,{p},Loop]

@ -8,7 +8,7 @@ codetoanalyze/objc/pulse/MemoryLeaks.m, call_bridge_interproc_leak_ok_FP, 2, MEM
codetoanalyze/objc/pulse/MemoryLeaks.m, call_cfrelease_interproc_leak_ok_FP, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by call to `CFLocaleCreate` (modelled),allocation part of the trace ends here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaksInBlocks.m, block_captured_var_leak_bad, 6, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by call to `malloc_no_fail` (modelled),allocation part of the trace ends here,memory becomes unreachable here]
codetoanalyze/objc/pulse/NPEBlocks.m, Singleton.dispatch_once_no_npe_good_FP, 6, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,invalid access occurs here]
codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,when calling `objc_blockcaptured_npe_bad_2` here,parameter `x` of objc_blockcaptured_npe_bad_2,invalid access occurs here]
codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,when calling `objc_blockcaptured_npe_bad_3` here,parameter `x` of objc_blockcaptured_npe_bad_3,invalid access occurs here]
codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_ok_FP, 6, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,invalid access occurs here]
codetoanalyze/objc/pulse/use_after_free.m, PulseTest.use_after_free_simple_in_objc_method_bad:, 2, USE_AFTER_FREE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `x` of PulseTest.use_after_free_simple_in_objc_method_bad:,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of PulseTest.use_after_free_simple_in_objc_method_bad:,invalid access occurs here]
codetoanalyze/objc/pulse/use_after_free.m, use_after_free_simple_bad, 2, USE_AFTER_FREE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `x` of use_after_free_simple_bad,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of use_after_free_simple_bad,invalid access occurs here]

@ -33,7 +33,7 @@ digraph cfg {
"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_3" -> "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_2" ;
"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" [label="4: Message Call: foo:and: \n n$4=*&self:B* [line 23, column 10]\n n$5=*n$4.h:int [line 23, column 10]\n n$2=*&self:B* const [line 24, column 11]\n n$6=_fun_B.foo:and:[objc_blockB.f_1](n$5:int,n$2:B* const ) block_params [line 23, column 3]\n " shape="box"]
"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" [label="4: Message Call: foo:and: \n n$4=*&self:B* [line 23, column 10]\n n$5=*n$4.h:int [line 23, column 10]\n n$2=*&self:B* const [line 24, column 11]\n n$6=_fun_B.foo:and:[objc_blockB.f_1](n$5:int,n$2:B* const ) [line 23, column 3]\n " shape="box"]
"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" -> "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_3" ;

@ -63,7 +63,7 @@ digraph cfg {
"array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_2" [label="2: Exit MyBlock.array \n " color=yellow style=filled]
"array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" [label="3: Message Call: enumerateObjectsUsingBlock: \n n$5=*&a:NSArray* [line 19, column 4]\n n$6=_fun_NSArray.enumerateObjectsUsingBlock:[objc_blockMyBlock.array_1](n$5:NSArray*) block_params virtual [line 19, column 3]\n " shape="box"]
"array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" [label="3: Message Call: enumerateObjectsUsingBlock: \n n$5=*&a:NSArray* [line 19, column 4]\n n$6=_fun_NSArray.enumerateObjectsUsingBlock:[objc_blockMyBlock.array_1](n$5:NSArray*) virtual [line 19, column 3]\n " shape="box"]
"array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" -> "array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_2" ;

@ -110,7 +110,7 @@ digraph cfg {
"block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_3" -> "block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_2" ;
"block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_4" [label="4: Call _fun__dispatch_once \n n$7=*&a:DispatchA* [line 37, column 24]\n n$9=_fun__dispatch_once[objc_blockDispatchA.block_attribute_2](&#GB<codetoanalyze/objc/shared/block/dispatch.m>$DispatchA.block_attribute.once:long*,n$7:DispatchA*) block_params [line 37, column 3]\n " shape="box"]
"block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_4" [label="4: Call _fun__dispatch_once \n n$7=*&a:DispatchA* [line 37, column 24]\n n$9=_fun__dispatch_once(&#GB<codetoanalyze/objc/shared/block/dispatch.m>$DispatchA.block_attribute.once:long*,(_fun_objc_blockDispatchA.block_attribute_2,([by ref]n$7 &a:DispatchA*)):_fn_(*)) [line 37, column 3]\n " shape="box"]
"block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_4" -> "block_attribute#DispatchA#class.df997e345dbf19ec3438c667c942e14a_3" ;
@ -190,7 +190,7 @@ digraph cfg {
"sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_3" -> "sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_2" ;
"sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_4" [label="4: Call _fun__dispatch_once \n n$4=_fun__dispatch_once[objc_blockDispatchA.sharedInstance_1](&#GB<codetoanalyze/objc/shared/block/dispatch.m>$DispatchA.sharedInstance.once:long*) block_params [line 28, column 3]\n " shape="box"]
"sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_4" [label="4: Call _fun__dispatch_once \n n$4=_fun__dispatch_once(&#GB<codetoanalyze/objc/shared/block/dispatch.m>$DispatchA.sharedInstance.once:long*,(_fun_objc_blockDispatchA.sharedInstance_1):_fn_(*)) [line 28, column 3]\n " shape="box"]
"sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_4" -> "sharedInstance#DispatchA#class.8992c6086d1ce5c225093940f62386ac_3" ;

@ -101,7 +101,7 @@ digraph cfg {
"dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_3" -> "dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_2" ;
"dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_4" [label="4: Call _fun_dispatch_after \n n$16=_fun_dispatch_time(0:unsigned long long,((unsigned long long)2 * 1000000000):long long) [line 46, column 18]\n n$17=_fun_dispatch_get_main_queue() [line 47, column 18]\n n$21=_fun_dispatch_after[objc_blockDispatchEx.dispatch_after_example_3](n$16:unsigned long long,n$17:NSObject*) block_params [line 46, column 3]\n " shape="box"]
"dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_4" [label="4: Call _fun_dispatch_after \n n$16=_fun_dispatch_time(0:unsigned long long,((unsigned long long)2 * 1000000000):long long) [line 46, column 18]\n n$17=_fun_dispatch_get_main_queue() [line 47, column 18]\n n$21=_fun_dispatch_after(n$16:unsigned long long,n$17:NSObject*,(_fun_objc_blockDispatchEx.dispatch_after_example_3):_fn_(*)) [line 46, column 3]\n " shape="box"]
"dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_4" -> "dispatch_after_example#DispatchEx#class.1d25856bd99eb1ef683c8f65ff46d05d_3" ;
@ -120,7 +120,7 @@ digraph cfg {
"dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_3" -> "dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_2" ;
"dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_4" [label="4: Call _fun_dispatch_async \n n$9=_fun_dispatch_get_global_queue(0:long,(unsigned long)0:unsigned long) [line 36, column 18]\n n$13=_fun_dispatch_async[objc_blockDispatchEx.dispatch_async_example_2](n$9:NSObject*) block_params [line 36, column 3]\n " shape="box"]
"dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_4" [label="4: Call _fun_dispatch_async \n n$9=_fun_dispatch_get_global_queue(0:long,(unsigned long)0:unsigned long) [line 36, column 18]\n n$13=_fun_dispatch_async(n$9:NSObject*,(_fun_objc_blockDispatchEx.dispatch_async_example_2):_fn_(*)) [line 36, column 3]\n " shape="box"]
"dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_4" -> "dispatch_async_example#DispatchEx#class.5c5d7347be2a9654ad7e32514189fe54_3" ;
@ -139,7 +139,7 @@ digraph cfg {
"dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_3" -> "dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_2" ;
"dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_4" [label="4: Call _fun_dispatch_barrier_async \n n$38=_fun_dispatch_get_main_queue() [line 75, column 26]\n n$42=_fun_dispatch_barrier_async[objc_blockDispatchEx.dispatch_barrier_example_6](n$38:NSObject*) block_params [line 75, column 3]\n " shape="box"]
"dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_4" [label="4: Call _fun_dispatch_barrier_async \n n$38=_fun_dispatch_get_main_queue() [line 75, column 26]\n n$42=_fun_dispatch_barrier_async(n$38:NSObject*,(_fun_objc_blockDispatchEx.dispatch_barrier_example_6):_fn_(*)) [line 75, column 3]\n " shape="box"]
"dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_4" -> "dispatch_barrier_example#DispatchEx#class.a541a40f2f04e29019c58e563f7544d8_3" ;
@ -158,7 +158,7 @@ digraph cfg {
"dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_3" -> "dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_2" ;
"dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_4" [label="4: Call _fun_dispatch_group_async \n n$24=_fun_dispatch_get_main_queue() [line 57, column 30]\n n$28=_fun_dispatch_group_async[objc_blockDispatchEx.dispatch_group_example_4](n$24:NSObject*,null:NSObject*) block_params [line 57, column 3]\n " shape="box"]
"dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_4" [label="4: Call _fun_dispatch_group_async \n n$24=_fun_dispatch_get_main_queue() [line 57, column 30]\n n$28=_fun_dispatch_group_async(null:NSObject*,n$24:NSObject*,(_fun_objc_blockDispatchEx.dispatch_group_example_4):_fn_(*)) [line 57, column 3]\n " shape="box"]
"dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_4" -> "dispatch_group_example#DispatchEx#class.f420a75c58eda6d3f0e5e05fadabfc18_3" ;
@ -177,7 +177,7 @@ digraph cfg {
"dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_3" -> "dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_2" ;
"dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_4" [label="4: Call _fun_dispatch_group_async \n n$31=_fun_dispatch_get_main_queue() [line 66, column 30]\n n$35=_fun_dispatch_group_async[objc_blockDispatchEx.dispatch_group_notify_example_5](n$31:NSObject*,null:NSObject*) block_params [line 66, column 3]\n " shape="box"]
"dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_4" [label="4: Call _fun_dispatch_group_async \n n$31=_fun_dispatch_get_main_queue() [line 66, column 30]\n n$35=_fun_dispatch_group_async(null:NSObject*,n$31:NSObject*,(_fun_objc_blockDispatchEx.dispatch_group_notify_example_5):_fn_(*)) [line 66, column 3]\n " shape="box"]
"dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_4" -> "dispatch_group_notify_example#DispatchEx#class.f5cf54b07621c319cf7ead3b217760ed_3" ;
@ -196,7 +196,7 @@ digraph cfg {
"dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_3" -> "dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_2" ;
"dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_4" [label="4: Call _fun__dispatch_once \n n$6=_fun__dispatch_once[objc_blockDispatchEx.dispatch_once_example_1](&#GB<codetoanalyze/objc/shared/block/dispatch_examples.m>$DispatchEx.dispatch_once_example.onceToken:long*) block_params [line 27, column 3]\n " shape="box"]
"dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_4" [label="4: Call _fun__dispatch_once \n n$6=_fun__dispatch_once(&#GB<codetoanalyze/objc/shared/block/dispatch_examples.m>$DispatchEx.dispatch_once_example.onceToken:long*,(_fun_objc_blockDispatchEx.dispatch_once_example_1):_fn_(*)) [line 27, column 3]\n " shape="box"]
"dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_4" -> "dispatch_once_example#DispatchEx#class.d3456446b1a2d5355c1767887cc8b62c_3" ;

@ -11,7 +11,7 @@ digraph cfg {
"DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_3" -> "DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_5" ;
"DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_4" [label="4: Call _fun__dispatch_once \n n$3=_fun__dispatch_once[objc_blockDispatchInMacroTest_1](&#GB<codetoanalyze/objc/shared/block/dispatch_in_macro.m>$DispatchInMacroTest.once_token:long*) block_params [line 21, column 10]\n " shape="box"]
"DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_4" [label="4: Call _fun__dispatch_once \n n$3=_fun__dispatch_once(&#GB<codetoanalyze/objc/shared/block/dispatch_in_macro.m>$DispatchInMacroTest.once_token:long*,(_fun_objc_blockDispatchInMacroTest_1):_fn_(*)) [line 21, column 10]\n " shape="box"]
"DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_4" -> "DispatchInMacroTest.f5d56763274a479d06265a2f9562bef1_3" ;

@ -1,6 +1,5 @@
codetoanalyze/objcpp/biabduction/BlockLfield.mm, A.mOk, 1, PRECONDITION_NOT_FOUND, no_bucket, ERROR, [start of procedure mOk]
codetoanalyze/objcpp/biabduction/BlockLfield.mm, CFunWithBlockOk, 2, PRECONDITION_NOT_MET, no_bucket, WARNING, [start of procedure CFunWithBlockOk()]
codetoanalyze/objcpp/biabduction/BlockLfield.mm, CFunWithBlockOk_objc_blockA.mOk_1, 2, PRECONDITION_NOT_MET, no_bucket, WARNING, [start of procedure CFunWithBlockOk()]
codetoanalyze/objcpp/biabduction/c_functions.mm, main, 4, NULL_DEREFERENCE, B5, ERROR, [start of procedure main(),start of procedure autoUpdating,return from a call to Functions.autoUpdating,start of procedure autoUpdating2,Skipping dispatch_once2(): method has no implementation,return from a call to Functions.autoUpdating2,start of procedure block,return from a call to Functions.block,start of procedure block,return from a call to objc_blockobjc_blockFunctions.autoUpdating_1_2,Message block with receiver nil returns nil.]
codetoanalyze/objcpp/biabduction/BlockLfield.mm, CFunWithBlockOk[objc_blockA.mOk_1], 2, PRECONDITION_NOT_MET, no_bucket, WARNING, [start of procedure CFunWithBlockOk()]
codetoanalyze/objcpp/biabduction/c_functions.mm, main, 4, NULL_DEREFERENCE, B5, ERROR, [start of procedure main(),start of procedure autoUpdating,start of procedure block,start of procedure setBlock:,return from a call to Functions.setBlock:,return from a call to objc_blockFunctions.autoUpdating_1,return from a call to Functions.autoUpdating,start of procedure autoUpdating2,return from a call to Functions.autoUpdating2,start of procedure block,return from a call to Functions.block,start of procedure block,return from a call to objc_blockobjc_blockFunctions.autoUpdating_1_2,Message block with receiver nil returns nil.]
codetoanalyze/objcpp/biabduction/retain_cycles/RetainCycleWithStruct.mm, Animation.tracer, 2, BIABDUCTION_ANALYSIS_STOPS, no_bucket, WARNING, [start of procedure tracer,start of procedure _State,return from a call to _State::_State,start of procedure initWithAnimation:,Taking true branch,return from a call to Tracer.initWithAnimation:]
codetoanalyze/objcpp/biabduction/retain_cycles/RetainCycleWithStruct.mm, Animation.tracer, 2, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure tracer,start of procedure _State,return from a call to _State::_State,start of procedure initWithAnimation:,Taking true branch,return from a call to Tracer.initWithAnimation:]

Loading…
Cancel
Save