[biabduction] Enable dynamic dispatch for ObjC methods

Reviewed By: jeremydubreil

Differential Revision: D8451526

fbshipit-source-id: 8fa2a1f
master
Dulma Churchill 7 years ago committed by Facebook Github Bot
parent 2cf0e7a1d2
commit 60cbc2c98e

@ -578,7 +578,7 @@ let specialize_types_proc callee_pdesc resolved_pdesc substitutions =
let resolved_pname = get_proc_name resolved_pdesc in let resolved_pname = get_proc_name resolved_pdesc in
let convert_pvar pvar = Pvar.mk (Pvar.get_name pvar) resolved_pname in let convert_pvar pvar = Pvar.mk (Pvar.get_name pvar) resolved_pname in
let mk_ptr_typ typename = let mk_ptr_typ typename =
(* Only consider pointers from Java objects for now *) (* Only consider pointers from objects for now *)
Typ.mk (Tptr (Typ.mk (Tstruct typename), Typ.Pk_pointer)) Typ.mk (Tptr (Typ.mk (Tstruct typename), Typ.Pk_pointer))
in in
let convert_exp = function let convert_exp = function
@ -618,16 +618,14 @@ let specialize_types_proc callee_pdesc resolved_pdesc substitutions =
Some set_instr Some set_instr
| Sil.Call | Sil.Call
( return_ids ( return_ids
, Exp.Const (Const.Cfun (Typ.Procname.Java callee_pname_java)) , Exp.Const (Const.Cfun callee_pname)
, (Exp.Var id, _) :: origin_args , (Exp.Var id, _) :: origin_args
, loc , loc
, call_flags ) , call_flags )
when call_flags.CallFlags.cf_virtual && redirect_typename id <> None -> when call_flags.CallFlags.cf_virtual && redirect_typename id <> None ->
let redirected_typename = Option.value_exn (redirect_typename id) in let redirected_typename = Option.value_exn (redirect_typename id) in
let redirected_typ = mk_ptr_typ redirected_typename in let redirected_typ = mk_ptr_typ redirected_typename in
let redirected_pname = let redirected_pname = Typ.Procname.replace_class callee_pname redirected_typename in
Typ.Procname.replace_class (Typ.Procname.Java callee_pname_java) redirected_typename
in
let args = let args =
let other_args = List.map ~f:(fun (exp, typ) -> (convert_exp exp, typ)) origin_args in let other_args = List.map ~f:(fun (exp, typ) -> (convert_exp exp, typ)) origin_args in
(Exp.Var id, redirected_typ) :: other_args (Exp.Var id, redirected_typ) :: other_args
@ -657,29 +655,56 @@ let specialize_types_proc callee_pdesc resolved_pdesc substitutions =
convert_cfg ~callee_pdesc ~resolved_pdesc ~f_instr_list convert_cfg ~callee_pdesc ~resolved_pdesc ~f_instr_list
exception UnmatchedParameters
(** Creates a copy of a procedure description and a list of type substitutions of the form (** Creates a copy of a procedure description and a list of type substitutions of the form
(name, typ) where name is a parameter. The resulting proc desc is isomorphic but (name, typ) where name is a parameter. The resulting proc desc is isomorphic but
all the type of the parameters are replaced in the instructions according to the list. 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 *) The virtual calls are also replaced to match the parameter types *)
let specialize_types callee_pdesc resolved_pname args = let specialize_types ?(has_clang_model= false) callee_pdesc resolved_pname args =
let callee_attributes = get_attributes callee_pdesc in let callee_attributes = get_attributes callee_pdesc in
let resolved_params, substitutions = let resolved_params, substitutions =
List.fold2_exn try
~f:(fun (params, subts) (param_name, param_typ) (_, arg_typ) -> List.fold2_exn
match arg_typ.Typ.desc with ~f:(fun (params, subts) (param_name, param_typ) (_, arg_typ) ->
| Tptr ({desc= Tstruct typename}, Pk_pointer) -> match arg_typ.Typ.desc with
(* Replace the type of the parameter by the type of the argument *) | Tptr ({desc= Tstruct typename}, Pk_pointer) ->
((param_name, arg_typ) :: params, Mangled.Map.add param_name typename subts) (* Replace the type of the parameter by the type of the argument *)
| _ -> ((param_name, arg_typ) :: params, Mangled.Map.add param_name typename subts)
((param_name, param_typ) :: params, subts) ) | _ ->
~init:([], Mangled.Map.empty) callee_attributes.formals args ((param_name, param_typ) :: params, subts) )
~init:([], Mangled.Map.empty) callee_attributes.formals args
with Invalid_argument _ ->
L.internal_error
"Call mismatch: method %a has %i paramters but is called with %i arguments@."
Typ.Procname.pp resolved_pname
(List.length callee_attributes.formals)
(List.length args) ;
raise UnmatchedParameters
in
let translation_unit =
(* If it is a model, and we are using the procdesc stored in the summary, the default translation unit
won't be useful because we don't store that tenv, so we aim to find the source file of the caller to
use its tenv. *)
if has_clang_model then
let pname = get_proc_name callee_pdesc in
match Attributes.find_file_capturing_procedure pname with
| Some (source_file, _) ->
source_file
| None ->
Logging.die InternalError
"specialize_types should only be called with defined procedures, but we cannot find \
the captured file of procname %a"
Typ.Procname.pp pname
else callee_attributes.translation_unit
in in
let resolved_attributes = let resolved_attributes =
{ callee_attributes with { callee_attributes with
formals= List.rev resolved_params formals= List.rev resolved_params
; proc_name= resolved_pname ; proc_name= resolved_pname
; is_specialized= true ; is_specialized= true
; err_log= Errlog.empty () } ; err_log= Errlog.empty ()
; translation_unit }
in in
Attributes.store resolved_attributes ; Attributes.store resolved_attributes ;
let resolved_pdesc = from_proc_attributes resolved_attributes in let resolved_pdesc = from_proc_attributes resolved_attributes in

@ -223,7 +223,9 @@ val is_captured_var : t -> Pvar.t -> bool
val has_modify_in_block_attr : t -> Pvar.t -> bool val has_modify_in_block_attr : t -> Pvar.t -> bool
val specialize_types : t -> Typ.Procname.t -> (Exp.t * Typ.t) list -> t exception UnmatchedParameters
val specialize_types : ?has_clang_model:bool -> t -> Typ.Procname.t -> (Exp.t * Typ.t) list -> t
(** Creates a copy of a procedure description and a list of type substitutions of the form (** Creates a copy of a procedure description and a list of type substitutions of the form
(name, typ) where name is a parameter. The resulting procdesc is isomorphic but (name, 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. all the type of the parameters are replaced in the instructions according to the list.

@ -951,6 +951,10 @@ module Procname = struct
is_c_function name is_c_function name
let is_objc_method procname =
match procname with ObjC_Cpp name -> ObjC_Cpp.is_objc_method name | _ -> false
let block_name_of_procname procname = let block_name_of_procname procname =
match procname with match procname with
| Block block -> | Block block ->

@ -473,6 +473,8 @@ being the name of the struct, [None] means the parameter is of some other type.
val parameter_of_name : t -> Name.t -> Parameter.t val parameter_of_name : t -> Name.t -> Parameter.t
val is_objc_method : t -> bool
(** Hash tables with proc names as keys. *) (** Hash tables with proc names as keys. *)
module Hash : Caml.Hashtbl.S with type key = t module Hash : Caml.Hashtbl.S with type key = t

@ -624,19 +624,28 @@ let resolve_virtual_pname tenv prop actuals callee_pname call_flags : Typ.Procna
(** Resolve the name of the procedure to call based on the type of the arguments *) (** Resolve the name of the procedure to call based on the type of the arguments *)
let resolve_pname tenv prop args pname call_flags : Typ.Procname.t = let resolve_pname ~caller_pdesc tenv prop args pname call_flags : Typ.Procname.t =
let resolve_from_args resolved_pname args = let resolve_from_args resolved_pname args =
let resolved_parameters = Typ.Procname.get_parameters resolved_pname in
let resolved_params = let resolved_params =
List.fold2_exn try
~f:(fun accu (arg_exp, _) name -> List.fold2_exn
match resolve_typename prop arg_exp with ~f:(fun accu (arg_exp, _) name ->
| Some class_name -> match resolve_typename prop arg_exp with
Typ.Procname.parameter_of_name resolved_pname class_name :: accu | Some class_name ->
| None -> Typ.Procname.parameter_of_name resolved_pname class_name :: accu
name :: accu ) | None ->
~init:[] args name :: accu )
(Typ.Procname.get_parameters resolved_pname) ~init:[] args resolved_parameters
|> List.rev |> List.rev
with Invalid_argument _ ->
let loc = (Procdesc.get_attributes caller_pdesc).loc in
let file = loc.Location.file in
L.internal_error
"Call mismatch: method %a has %i paramters but is called with %i arguments, in %a, %a@."
Typ.Procname.pp pname (List.length resolved_parameters) (List.length args) SourceFile.pp
file Location.pp loc ;
raise Procdesc.UnmatchedParameters
in in
Typ.Procname.replace_parameters resolved_params resolved_pname Typ.Procname.replace_parameters resolved_params resolved_pname
in in
@ -661,22 +670,44 @@ let resolve_pname tenv prop args pname call_flags : Typ.Procname.t =
| args when match_parameters args (* Static call *) -> | args when match_parameters args (* Static call *) ->
(pname, args) (pname, args)
| args -> | args ->
L.(die InternalError) let loc = (Procdesc.get_attributes caller_pdesc).loc in
"Call mismatch: method %a has %i paramters but is called with %i arguments@." let file = loc.Location.file in
Typ.Procname.pp pname (List.length parameters) (List.length args) L.internal_error
"Call mismatch: method %a has %i paramters but is called with %i arguments, in %a, %a@."
Typ.Procname.pp pname (List.length parameters) (List.length args) SourceFile.pp file
Location.pp loc ;
raise Procdesc.UnmatchedParameters
in in
resolve_from_args resolved_pname other_args resolve_from_args resolved_pname other_args
let resolve_args prop args =
List.map
~f:(fun ((arg_exp, arg_typ) as arg) ->
match (resolve_typename prop arg_exp, arg_typ.Typ.desc) with
| Some class_name, Tptr (({desc= Tstruct typename} as inner_typ), p) ->
let resolved_arg_typ =
if Typ.Name.equal class_name typename then arg_typ
else
let struct_typ = {inner_typ with desc= Tstruct class_name} in
({arg_typ with desc= Tptr (struct_typ, p)} : Typ.t)
in
(arg_exp, resolved_arg_typ)
| _ ->
arg )
args
(** Resolve the procedure name and run the analysis of the resolved procedure (** Resolve the procedure name and run the analysis of the resolved procedure
if not already analyzed *) if not already analyzed *)
let resolve_and_analyze tenv ~caller_pdesc prop args callee_proc_name call_flags let resolve_and_analyze tenv ~caller_pdesc ?(has_clang_model= false) prop args callee_proc_name
: Typ.Procname.t * Summary.t option = call_flags : Typ.Procname.t * (Procdesc.t option * Summary.t option) =
(* TODO (#15748878): Fix conflict with method overloading by encoding in the procedure name (* TODO (#15748878): Fix conflict with method overloading by encoding in the procedure name
whether the method is defined or generated by the specialization *) whether the method is defined or generated by the specialization *)
let analyze_ondemand resolved_pname : Summary.t option = let analyze_ondemand resolved_pname : Procdesc.t option * Summary.t option =
if Typ.Procname.equal resolved_pname callee_proc_name then if Typ.Procname.equal resolved_pname callee_proc_name then
Ondemand.analyze_proc_name ~caller_pdesc callee_proc_name ( Ondemand.get_proc_desc callee_proc_name
, Ondemand.analyze_proc_name ~caller_pdesc callee_proc_name )
else else
(* Create the type sprecialized procedure description and analyze it directly *) (* Create the type sprecialized procedure description and analyze it directly *)
let analyze specialized_pdesc = Ondemand.analyze_proc_desc ~caller_pdesc specialized_pdesc in let analyze specialized_pdesc = Ondemand.analyze_proc_desc ~caller_pdesc specialized_pdesc in
@ -685,14 +716,29 @@ let resolve_and_analyze tenv ~caller_pdesc prop args callee_proc_name call_flags
| Some resolved_proc_desc -> | Some resolved_proc_desc ->
Some resolved_proc_desc Some resolved_proc_desc
| None -> | None ->
let procdesc_opt =
(* If it is a model, we aim to get the procdesc stored in a summary rather than the
(empty) procdesc stored in the caller's cfg. *)
if has_clang_model then
match Summary.get callee_proc_name with
| Some summary ->
Some (Summary.get_proc_desc summary)
| None ->
Ondemand.get_proc_desc callee_proc_name
else Ondemand.get_proc_desc callee_proc_name
in
Option.map Option.map
~f:(fun callee_proc_desc -> ~f:(fun callee_proc_desc ->
Procdesc.specialize_types callee_proc_desc resolved_pname args ) (* It is possible that the types of the arguments are not as precise as the type of the objects
(Ondemand.get_proc_desc callee_proc_name) in the heap, so we should update them to get the best results. *)
let resolved_args = resolve_args prop args in
Procdesc.specialize_types ~has_clang_model callee_proc_desc resolved_pname
resolved_args )
procdesc_opt
in in
Option.bind resolved_proc_desc_option ~f:analyze (resolved_proc_desc_option, Option.bind resolved_proc_desc_option ~f:analyze)
in in
let resolved_pname = resolve_pname tenv prop args callee_proc_name call_flags in let resolved_pname = resolve_pname ~caller_pdesc tenv prop args callee_proc_name call_flags in
(resolved_pname, analyze_ondemand resolved_pname) (resolved_pname, analyze_ondemand resolved_pname)
@ -1049,6 +1095,64 @@ let execute_store ?(report_deref_errors= true) pname pdesc tenv lhs_exp typ rhs_
with Rearrange.ARRAY_ACCESS -> if Int.equal Config.array_level 0 then assert false else [prop_] with Rearrange.ARRAY_ACCESS -> if Int.equal Config.array_level 0 then assert false else [prop_]
let is_variadic_procname callee_pname =
Option.value_map
(Ondemand.get_proc_desc callee_pname)
~f:(fun proc_desc -> (Procdesc.get_attributes proc_desc).ProcAttributes.is_variadic)
~default:false
let resolve_and_analyze_no_dynamic_dispatch current_pdesc tenv prop_r n_actual_params callee_pname
call_flags =
let resolved_pname =
match resolve_virtual_pname tenv prop_r n_actual_params callee_pname call_flags with
| resolved_pname :: _ ->
resolved_pname
| [] ->
callee_pname
in
let resolved_summary_opt =
Ondemand.analyze_proc_name ~caller_pdesc:current_pdesc resolved_pname
in
(resolved_pname, (Ondemand.get_proc_desc resolved_pname, resolved_summary_opt))
let resolve_and_analyze_clang current_pdesc tenv prop_r n_actual_params callee_pname call_flags =
if
Config.dynamic_dispatch && not (is_variadic_procname callee_pname)
&& Typ.Procname.is_objc_method callee_pname
(* to be extended to other methods *)
then
try
let has_clang_model = Summary.has_model callee_pname in
let resolved_pname, (resolved_pdesc_opt, resolved_summary_opt) =
resolve_and_analyze tenv ~caller_pdesc:current_pdesc ~has_clang_model prop_r
n_actual_params callee_pname call_flags
in
(* It could be useful to specialize a model, but also it could cause a failure,
because we don't have the correct fields in the tenv.
In that case, default to the non-specialized spec for the model. *)
let clang_model_specialized_failure =
match resolved_summary_opt with
| Some summary when has_clang_model ->
List.is_empty (Tabulation.get_specs_from_payload summary)
| None ->
true
| _ ->
false
in
if clang_model_specialized_failure then
resolve_and_analyze_no_dynamic_dispatch current_pdesc tenv prop_r n_actual_params
callee_pname call_flags
else (resolved_pname, (resolved_pdesc_opt, resolved_summary_opt))
with Procdesc.UnmatchedParameters ->
resolve_and_analyze_no_dynamic_dispatch current_pdesc tenv prop_r n_actual_params
callee_pname call_flags
else
resolve_and_analyze_no_dynamic_dispatch current_pdesc tenv prop_r n_actual_params callee_pname
call_flags
(** Execute [instr] with a symbolic heap [prop].*) (** Execute [instr] with a symbolic heap [prop].*)
let rec sym_exec exe_env tenv current_pdesc instr_ (prop_: Prop.normal Prop.t) path let rec sym_exec exe_env tenv current_pdesc instr_ (prop_: Prop.normal Prop.t) path
: (Prop.normal Prop.t * Paths.Path.t) list = : (Prop.normal Prop.t * Paths.Path.t) list =
@ -1180,7 +1284,7 @@ let rec sym_exec exe_env tenv current_pdesc instr_ (prop_: Prop.normal Prop.t) p
skip_call ~reason norm_prop path skipped_pname ret_annots loc ret_id_typ ret_type skip_call ~reason norm_prop path skipped_pname ret_annots loc ret_id_typ ret_type
norm_args norm_args
in in
let resolved_pname, resolved_summary_opt = let resolved_pname, (_, resolved_summary_opt) =
resolve_and_analyze tenv ~caller_pdesc:current_pdesc norm_prop norm_args callee_pname resolve_and_analyze tenv ~caller_pdesc:current_pdesc norm_prop norm_args callee_pname
call_flags call_flags
in in
@ -1229,18 +1333,11 @@ let rec sym_exec exe_env tenv current_pdesc instr_ (prop_: Prop.normal Prop.t) p
| _ -> | _ ->
(* Generic fun call with known name *) (* Generic fun call with known name *)
let prop_r, n_actual_params = normalize_params tenv current_pname prop_ actual_params in let prop_r, n_actual_params = normalize_params tenv current_pname prop_ actual_params in
let resolved_pname =
match resolve_virtual_pname tenv prop_r n_actual_params callee_pname call_flags with
| resolved_pname :: _ ->
resolved_pname
| [] ->
callee_pname
in
(* method with block parameters *) (* method with block parameters *)
let with_block_parameters_summary_opt = let with_block_parameters_summary_opt =
if call_flags.CallFlags.cf_with_block_parameters then if call_flags.CallFlags.cf_with_block_parameters then
SymExecBlocks.resolve_method_with_block_args_and_analyze ~caller_pdesc:current_pdesc SymExecBlocks.resolve_method_with_block_args_and_analyze ~caller_pdesc:current_pdesc
resolved_pname actual_params callee_pname actual_params
else None else None
in in
match with_block_parameters_summary_opt with match with_block_parameters_summary_opt with
@ -1250,22 +1347,24 @@ let rec sym_exec exe_env tenv current_pdesc instr_ (prop_: Prop.normal Prop.t) p
in in
Logging.d_strln "Calling method specialized with blocks... " ; Logging.d_strln "Calling method specialized with blocks... " ;
proc_call exe_env resolved_summary proc_call exe_env resolved_summary
(call_args prop_r resolved_pname n_extended_actual_params ret_id_typ loc) (call_args prop_r callee_pname n_extended_actual_params ret_id_typ loc)
| None -> | None ->
(* Generic fun call with known name *) (* Generic fun call with known name *)
let resolved_summary_opt = let resolved_pname, (resolved_pdesc_opt, resolved_summary_opt) =
Ondemand.analyze_proc_name ~caller_pdesc:current_pdesc resolved_pname resolve_and_analyze_clang current_pdesc tenv prop_r n_actual_params callee_pname
call_flags
in in
let callee_pdesc_opt = Ondemand.get_proc_desc resolved_pname in Logging.d_strln ("Original callee " ^ Typ.Procname.to_unique_id callee_pname) ;
Logging.d_strln ("Resolved callee " ^ Typ.Procname.to_unique_id resolved_pname) ;
let sentinel_result = let sentinel_result =
if Language.curr_language_is Clang then if Language.curr_language_is Clang then
check_variadic_sentinel_if_present check_variadic_sentinel_if_present
(call_args prop_r callee_pname actual_params ret_id_typ loc) (call_args prop_r resolved_pname actual_params ret_id_typ loc)
else [(prop_r, path)] else [(prop_r, path)]
in in
let do_call (prop, path) = let do_call (prop, path) =
let callee_desc = let callee_desc =
match (resolved_summary_opt, callee_pdesc_opt) with match (resolved_summary_opt, resolved_pdesc_opt) with
| Some summary, _ -> | Some summary, _ ->
`Summary summary `Summary summary
| None, Some pdesc -> | None, Some pdesc ->
@ -1286,21 +1385,23 @@ let rec sym_exec exe_env tenv current_pdesc instr_ (prop_: Prop.normal Prop.t) p
| None -> | None ->
load_ret_annots resolved_pname load_ret_annots resolved_pname
in in
match callee_pdesc_opt with match resolved_pdesc_opt with
| Some callee_pdesc | Some resolved_pdesc
-> ( -> (
let attrs = Procdesc.get_attributes callee_pdesc in let attrs = Procdesc.get_attributes resolved_pdesc in
let ret_type = attrs.ProcAttributes.ret_type in let ret_type = attrs.ProcAttributes.ret_type in
let model_as_malloc = Objc_models.is_malloc_model ret_type callee_pname in let model_as_malloc =
Objc_models.is_malloc_model ret_type resolved_pname
in
match (attrs.ProcAttributes.objc_accessor, model_as_malloc) with match (attrs.ProcAttributes.objc_accessor, model_as_malloc) with
| Some objc_accessor, _ -> | Some objc_accessor, _ ->
(* If it's an ObjC getter or setter, call the builtin rather than skipping *) (* If it's an ObjC getter or setter, call the builtin rather than skipping *)
handle_objc_instance_method_call n_actual_params n_actual_params prop handle_objc_instance_method_call n_actual_params n_actual_params prop
tenv (fst ret_id_typ) current_pdesc callee_pname loc path tenv (fst ret_id_typ) current_pdesc resolved_pname loc path
(sym_exec_objc_accessor callee_pname objc_accessor ret_type) (sym_exec_objc_accessor resolved_pname objc_accessor ret_type)
| None, true -> | None, true ->
(* If it's an alloc model, call alloc rather than skipping *) (* If it's an alloc model, call alloc rather than skipping *)
sym_exec_alloc_model exe_env callee_pname ret_type tenv ret_id_typ sym_exec_alloc_model exe_env resolved_pname ret_type tenv ret_id_typ
current_pdesc loc prop path current_pdesc loc prop path
| None, false -> | None, false ->
let is_objc_instance_method = let is_objc_instance_method =

@ -1456,9 +1456,9 @@ let exe_function_call exe_env callee_summary tenv ret_id caller_pdesc callee_pna
let spec_list, formal_params = spec_find_rename trace_call callee_summary in let spec_list, formal_params = spec_find_rename trace_call callee_summary in
let nspecs = List.length spec_list in let nspecs = List.length spec_list in
L.d_strln L.d_strln
(F.sprintf "Found %d specs for function %s" nspecs (Typ.Procname.to_string callee_pname)) ; (F.sprintf "Found %d specs for function %s" nspecs (Typ.Procname.to_unique_id callee_pname)) ;
L.d_strln L.d_strln
(F.sprintf "START EXECUTING SPECS FOR %s from state" (Typ.Procname.to_string callee_pname)) ; (F.sprintf "START EXECUTING SPECS FOR %s from state" (Typ.Procname.to_unique_id callee_pname)) ;
Prop.d_prop prop ; Prop.d_prop prop ;
L.d_ln () ; L.d_ln () ;
let exe_one_spec (n, spec) = let exe_one_spec (n, spec) =

@ -37,7 +37,7 @@ let all_checkers =
; { name= "biabduction" ; { name= "biabduction"
; active= Config.biabduction ; active= Config.biabduction
; callbacks= ; callbacks=
[ (Procedure Interproc.analyze_procedure, Language.Clang) [ (DynamicDispatch Interproc.analyze_procedure, Language.Clang)
; (DynamicDispatch Interproc.analyze_procedure, Language.Java) ] } ; (DynamicDispatch Interproc.analyze_procedure, Language.Java) ] }
; { name= "buffer overrun" ; { name= "buffer overrun"
; active= Config.bufferoverrun && not Config.cost (* Cost analysis already triggers Inferbo *) ; active= Config.bufferoverrun && not Config.cost (* Cost analysis already triggers Inferbo *)

@ -27,6 +27,7 @@ SOURCES_DEFAULT = \
memory_leaks_benchmark/RetainReleaseExampleBucketing.m \ memory_leaks_benchmark/RetainReleaseExampleBucketing.m \
memory_leaks_benchmark/CoreVideoExample.m \ memory_leaks_benchmark/CoreVideoExample.m \
memory_leaks_benchmark/RetainCycleLength3.m \ memory_leaks_benchmark/RetainCycleLength3.m \
npe/dynamic_dispatch.m \
npe/Fraction.m \ npe/Fraction.m \
npe/NPD_core_foundation.m \ npe/NPD_core_foundation.m \
npe/Npe_with_equal_names.m \ npe/Npe_with_equal_names.m \

@ -71,6 +71,7 @@ codetoanalyze/objc/errors/subtyping/KindOfClassExample.m, shouldThrowDivideByZer
codetoanalyze/objc/errors/subtyping/KindOfClassExample.m, shouldThrowDivideByZero2, 2, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure shouldThrowDivideByZero2(),start of procedure init,return from a call to Base_init,start of procedure returnsZero2(),Taking false branch,return from a call to returnsZero2] codetoanalyze/objc/errors/subtyping/KindOfClassExample.m, shouldThrowDivideByZero2, 2, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure shouldThrowDivideByZero2(),start of procedure init,return from a call to Base_init,start of procedure returnsZero2(),Taking false branch,return from a call to returnsZero2]
codetoanalyze/objc/errors/subtyping/KindOfClassExample.m, shouldThrowDivideByZero3, 3, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure shouldThrowDivideByZero3(),start of procedure init,return from a call to Derived_init,Taking true branch] codetoanalyze/objc/errors/subtyping/KindOfClassExample.m, shouldThrowDivideByZero3, 3, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure shouldThrowDivideByZero3(),start of procedure init,return from a call to Derived_init,Taking true branch]
codetoanalyze/objc/errors/variadic_methods/premature_nil_termination.m, PrematureNilTermA_nilInArrayWithObjects, 5, PREMATURE_NIL_TERMINATION_ARGUMENT, B1, ERROR, [start of procedure nilInArrayWithObjects] codetoanalyze/objc/errors/variadic_methods/premature_nil_termination.m, PrematureNilTermA_nilInArrayWithObjects, 5, PREMATURE_NIL_TERMINATION_ARGUMENT, B1, ERROR, [start of procedure nilInArrayWithObjects]
objc/src/CADisplayLink.m, CADisplayLink_displayLinkWithTarget:selector:, 3, Missing_fld, no_bucket, ERROR, [start of procedure displayLinkWithTarget:selector:]
codetoanalyze/objc/errors/memory_leaks_benchmark/CoreVideoExample.m, CoreVideoExample_cvpixelbuffer_not_released_leak, 1, MEMORY_LEAK, no_bucket, ERROR, [start of procedure cvpixelbuffer_not_released_leak] codetoanalyze/objc/errors/memory_leaks_benchmark/CoreVideoExample.m, CoreVideoExample_cvpixelbuffer_not_released_leak, 1, MEMORY_LEAK, no_bucket, ERROR, [start of procedure cvpixelbuffer_not_released_leak]
codetoanalyze/objc/errors/memory_leaks_benchmark/NSData_models_tests.m, NSData_models_tests_macForIV:, 2, MEMORY_LEAK, no_bucket, ERROR, [start of procedure macForIV:] codetoanalyze/objc/errors/memory_leaks_benchmark/NSData_models_tests.m, NSData_models_tests_macForIV:, 2, MEMORY_LEAK, no_bucket, ERROR, [start of procedure macForIV:]
codetoanalyze/objc/errors/memory_leaks_benchmark/NSString_models_tests.m, StringInitA_hexStringValue, 11, MEMORY_LEAK, no_bucket, ERROR, [start of procedure hexStringValue,Skipping CFStringCreateWithBytesNoCopy(): method has no implementation,Taking false branch] codetoanalyze/objc/errors/memory_leaks_benchmark/NSString_models_tests.m, StringInitA_hexStringValue, 11, MEMORY_LEAK, no_bucket, ERROR, [start of procedure hexStringValue,Skipping CFStringCreateWithBytesNoCopy(): method has no implementation,Taking false branch]
@ -82,6 +83,7 @@ codetoanalyze/objc/errors/npe/block.m, BlockA_foo, 5, NULL_DEREFERENCE, B1, ERRO
codetoanalyze/objc/errors/npe/block.m, BlockA_foo3:, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure foo3:] codetoanalyze/objc/errors/npe/block.m, BlockA_foo3:, 3, NULL_DEREFERENCE, B1, ERROR, [start of procedure foo3:]
codetoanalyze/objc/errors/npe/block.m, BlockA_foo4:, 6, NULL_DEREFERENCE, B1, ERROR, [start of procedure foo4:] codetoanalyze/objc/errors/npe/block.m, BlockA_foo4:, 6, NULL_DEREFERENCE, B1, ERROR, [start of procedure foo4:]
codetoanalyze/objc/errors/npe/block.m, BlockA_foo7, 2, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure foo7] codetoanalyze/objc/errors/npe/block.m, BlockA_foo7, 2, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure foo7]
codetoanalyze/objc/errors/npe/dynamic_dispatch.m, DynamicDispatchMain_npe_bad, 2, NULL_DEREFERENCE, B5, ERROR, [start of procedure npe_bad,start of procedure get_ddclass_from:,start of procedure get_ddclass,return from a call to PInstance_get_ddclass,return from a call to DynamicDispatchMain_get_ddclass_from:]
codetoanalyze/objc/errors/npe/ivar_blocks.m, MyClass_ivar_npe, 1, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure ivar_npe] codetoanalyze/objc/errors/npe/ivar_blocks.m, MyClass_ivar_npe, 1, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure ivar_npe]
codetoanalyze/objc/errors/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/errors/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/errors/property/main.c, property_main, 3, MEMORY_LEAK, no_bucket, ERROR, [start of procedure property_main(),Skipping aProperty: method has no implementation] codetoanalyze/objc/errors/property/main.c, property_main, 3, MEMORY_LEAK, no_bucket, ERROR, [start of procedure property_main(),Skipping aProperty: method has no implementation]

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/NSObject.h>
@interface DynamicDispatchClass : NSObject
@end
@implementation DynamicDispatchClass {
@public
int x;
}
@end
@protocol P
- (DynamicDispatchClass*)get_ddclass;
@end
@interface PInstance : NSObject<P>
@end
@implementation PInstance
- (DynamicDispatchClass*)get_ddclass {
return nil;
}
@end
@interface DynamicDispatchMain : NSObject
@end
@implementation DynamicDispatchMain
- (DynamicDispatchClass*)get_ddclass_from:(id<P>)object {
return [object get_ddclass];
}
- (int)npe_bad {
PInstance* object = [PInstance new];
return [self get_ddclass_from:object] -> x;
}
@end
Loading…
Cancel
Save