[ios] Capture the signature of getters and setters from headers.

Reviewed By: akotulski

Differential Revision: D4612126

fbshipit-source-id: 95c3f36
master
Dulma Churchill 8 years ago committed by Facebook Github Bot
parent 60f732bf7e
commit f549d58625

@ -16,18 +16,31 @@ let module F = Format;
let module L = Logging; let module L = Logging;
type attr_kind =
| ProcDefined
| ProcObjCAccessor
| ProcUndefined
[@@deriving compare];
/** Module to manage the table of attributes. */ /** Module to manage the table of attributes. */
let serializer: Serialization.serializer ProcAttributes.t = Serialization.create_serializer Serialization.Key.attributes; let serializer: Serialization.serializer ProcAttributes.t = Serialization.create_serializer Serialization.Key.attributes;
let attributes_filename defined::defined pname_file => let attributes_filename proc_kind::proc_kind pname_file => {
pname_file ^ (defined ? ".attr" : ".decl.attr"); let file_suffix =
switch proc_kind {
| ProcDefined => ".attr"
| ProcObjCAccessor => ".objc_acc.attr"
| ProcUndefined => ".decl.attr"
};
pname_file ^ file_suffix
};
/** path to the .attr file for the given procedure in the current results directory */ /** path to the .attr file for the given procedure in the current results directory */
let res_dir_attr_filename defined::defined pname => { let res_dir_attr_filename proc_kind::proc_kind pname => {
let pname_file = Procname.to_filename pname; let pname_file = Procname.to_filename pname;
let attr_fname = attributes_filename defined::defined pname_file; let attr_fname = attributes_filename proc_kind::proc_kind pname_file;
let bucket_dir = { let bucket_dir = {
let base = pname_file; let base = pname_file;
let len = String.length base; let len = String.length base;
@ -47,46 +60,94 @@ let res_dir_attr_filename defined::defined pname => {
/* Load the proc attribute for the defined filename if it exists, /* Load the proc attribute for the defined filename if it exists,
otherwise try to load the declared filename. */ otherwise try to load the declared filename. */
let load_attr defined_only::defined_only proc_name => { let load_attr defined_only::defined_only proc_name => {
let attributes_file defined::defined proc_name => Multilinks.resolve ( let attributes_file proc_kind::proc_kind proc_name => Multilinks.resolve (
res_dir_attr_filename defined::defined proc_name res_dir_attr_filename proc_kind::proc_kind proc_name
); );
let attr = Serialization.read_from_file serializer (attributes_file defined::true proc_name); let attr =
Serialization.read_from_file serializer (attributes_file proc_kind::ProcDefined proc_name);
if (is_none attr && not defined_only) { if (is_none attr && not defined_only) {
Serialization.read_from_file serializer (attributes_file defined::false proc_name) /* We try to load the objc accesor one if they exist, if not then we load the undefined one */
let attr =
Serialization.read_from_file
serializer (attributes_file proc_kind::ProcObjCAccessor proc_name);
switch attr {
| Some attr => Some attr
| None =>
Serialization.read_from_file serializer (attributes_file proc_kind::ProcUndefined proc_name)
}
} else { } else {
attr attr
} }
}; };
let create_proc_kind (proc_attributes: ProcAttributes.t) =>
if proc_attributes.is_defined {
ProcDefined
} else if (
Option.is_some proc_attributes.objc_accessor
) {
ProcObjCAccessor
} else {
ProcUndefined
};
let less_relevant_proc_kinds proc_kind =>
switch proc_kind {
| ProcDefined => [ProcObjCAccessor, ProcUndefined]
| ProcObjCAccessor => [ProcUndefined]
| ProcUndefined => []
};
/* Write a proc attributes to file. /* Write a proc attributes to file.
If defined, delete the declared file if it exists. */ If defined, delete the declared file if it exists. */
let write_and_delete proc_name (proc_attributes: ProcAttributes.t) => { let write_and_delete proc_name (proc_attributes: ProcAttributes.t) => {
let attributes_file defined => res_dir_attr_filename defined::defined proc_name; let proc_kind = create_proc_kind proc_attributes;
Serialization.write_to_file let attributes_file proc_kind => res_dir_attr_filename proc_kind::proc_kind proc_name;
serializer (attributes_file proc_attributes.is_defined) data::proc_attributes; Serialization.write_to_file serializer (attributes_file proc_kind) data::proc_attributes;
if proc_attributes.is_defined { let upgrade_relevance less_relevant_proc_kind => {
let fname_declared = DB.filename_to_string (attributes_file false); let fname_declared = DB.filename_to_string (attributes_file less_relevant_proc_kind);
if (Sys.file_exists fname_declared == `Yes) { if (Sys.file_exists fname_declared == `Yes) {
try (Unix.unlink fname_declared) { try (Unix.unlink fname_declared) {
| Unix.Unix_error _ => () | Unix.Unix_error _ => ()
} }
} }
} };
List.iter f::upgrade_relevance (less_relevant_proc_kinds proc_kind)
}; };
/* This creates an ordering in the attribute files: 1.defined, 2.objc accessor, 3.else.
To be used to figure out if we should override an existing attribute file with a new
one, if relevant information will be updated, or lost.
If the relevance is not upgraded, choose based on whether its associated file has higher
rank (alphabetically) than the other. */
let should_override_attr (new_attr: ProcAttributes.t) (old_attr: ProcAttributes.t) =>
if new_attr.is_defined {
if old_attr.is_defined {
SourceFile.compare new_attr.loc.file old_attr.loc.file > 0
} else {
true /* new becomes defined, override */
}
} else if
old_attr.is_defined {
false /* old was defined, new isn't, don't override */
} else if (
Option.is_some new_attr.objc_accessor
) {
if (Option.is_some old_attr.objc_accessor) {
SourceFile.compare new_attr.loc.file old_attr.loc.file > 0
} else {
true /* new becomes objc accessor, override */
}
} else {
false /* new isn't defined or objc accessor, don't overide */
};
let store_attributes (proc_attributes: ProcAttributes.t) => { let store_attributes (proc_attributes: ProcAttributes.t) => {
let proc_name = proc_attributes.proc_name; let proc_name = proc_attributes.proc_name;
let should_write = let should_write =
switch (load_attr defined_only::false proc_name) { switch (load_attr defined_only::false proc_name) {
| None => true | None => true
| Some proc_attributes_on_disk => | Some proc_attributes_on_disk => should_override_attr proc_attributes proc_attributes_on_disk
let higher_rank_than_on_disk () =>
proc_attributes.is_defined &&
SourceFile.compare proc_attributes.loc.file proc_attributes_on_disk.loc.file > 0;
let becomes_defined = proc_attributes.is_defined && not proc_attributes_on_disk.is_defined;
/* Only overwrite the attribute file if the procedure becomes defined
or its associated file has higher rank (alphabetically) than on disk. */
becomes_defined || higher_rank_than_on_disk ()
}; };
if should_write { if should_write {
write_and_delete proc_name proc_attributes write_and_delete proc_name proc_attributes

@ -568,16 +568,28 @@ let pp_variable_list fmt etl =>
f::(fun (id, ty) => Format.fprintf fmt " %a:%a" Mangled.pp id (Typ.pp_full Pp.text) ty) etl f::(fun (id, ty) => Format.fprintf fmt " %a:%a" Mangled.pp id (Typ.pp_full Pp.text) ty) etl
}; };
let pp_objc_accessor fmt accessor =>
switch accessor {
| Some (ProcAttributes.Objc_getter name) =>
Format.fprintf fmt "Getter of %a, " Ident.pp_fieldname name
| Some (ProcAttributes.Objc_setter name) =>
Format.fprintf fmt "Setter of %a, " Ident.pp_fieldname name
| None => ()
};
let pp_signature fmt pdesc => { let pp_signature fmt pdesc => {
let attributes = get_attributes pdesc;
let pname = get_proc_name pdesc; let pname = get_proc_name pdesc;
let pname_string = Procname.to_string pname; let pname_string = Procname.to_string pname;
let defined_string = is_defined pdesc ? "defined" : "undefined"; let defined_string = is_defined pdesc ? "defined" : "undefined";
Format.fprintf Format.fprintf
fmt fmt
"%s [%s, Return type: %s, Formals: %a, Locals: %a" "%s [%s, Return type: %s, %aFormals: %a, Locals: %a"
pname_string pname_string
defined_string defined_string
(Typ.to_string (get_ret_type pdesc)) (Typ.to_string (get_ret_type pdesc))
pp_objc_accessor
attributes.ProcAttributes.objc_accessor
pp_variable_list pp_variable_list
(get_formals pdesc) (get_formals pdesc)
pp_variable_list pp_variable_list
@ -585,7 +597,6 @@ let pp_signature fmt pdesc => {
if (not (List.is_empty (get_captured pdesc))) { if (not (List.is_empty (get_captured pdesc))) {
Format.fprintf fmt ", Captured: %a" pp_variable_list (get_captured pdesc) Format.fprintf fmt ", Captured: %a" pp_variable_list (get_captured pdesc)
}; };
let attributes = get_attributes pdesc;
let method_annotation = attributes.ProcAttributes.method_annotation; let method_annotation = attributes.ProcAttributes.method_annotation;
if (not (Annot.Method.is_empty method_annotation)) { if (not (Annot.Method.is_empty method_annotation)) {
Format.fprintf fmt ", Annotation: %a" (Annot.Method.pp pname_string) method_annotation Format.fprintf fmt ", Annotation: %a" (Annot.Method.pp pname_string) method_annotation

@ -72,49 +72,38 @@ struct
return_param_typ_opt false outer_context_opt extra_instrs return_param_typ_opt false outer_context_opt extra_instrs
| None -> () | None -> ()
let process_method_decl trans_unit_ctx tenv cg cfg curr_class meth_decl ~is_objc = let process_method_decl ?(set_objc_accessor_attr=false) trans_unit_ctx tenv cg cfg
curr_class meth_decl ~is_objc =
let ms, body_opt, extra_instrs = let ms, body_opt, extra_instrs =
CMethod_trans.method_signature_of_decl trans_unit_ctx tenv meth_decl None in CMethod_trans.method_signature_of_decl trans_unit_ctx tenv meth_decl None in
let is_instance = CMethod_signature.ms_is_instance ms in
let is_objc_inst_method = is_instance && is_objc in
match body_opt with match body_opt with
| Some body -> | Some body ->
let is_instance = CMethod_signature.ms_is_instance ms in
let procname = CMethod_signature.ms_get_name ms in let procname = CMethod_signature.ms_get_name ms in
let is_objc_inst_method = is_instance && is_objc in
let return_param_typ_opt = CMethod_signature.ms_get_return_param_typ ms in let return_param_typ_opt = CMethod_signature.ms_get_return_param_typ ms in
if CMethod_trans.create_local_procdesc if CMethod_trans.create_local_procdesc ~set_objc_accessor_attr
trans_unit_ctx cfg tenv ms [body] [] is_objc_inst_method then trans_unit_ctx cfg tenv ms [body] [] is_objc_inst_method then
add_method trans_unit_ctx tenv cg cfg curr_class procname body return_param_typ_opt add_method trans_unit_ctx tenv cg cfg curr_class procname body return_param_typ_opt
is_objc None extra_instrs is_objc None extra_instrs
| None -> () | None ->
if set_objc_accessor_attr then
ignore (CMethod_trans.create_local_procdesc ~set_objc_accessor_attr trans_unit_ctx
cfg tenv ms [] [] is_objc_inst_method)
let process_property_implementation cfg trans_unit_ctx obj_c_property_impl_decl_info = let process_property_implementation trans_unit_ctx tenv cg cfg curr_class
obj_c_property_impl_decl_info =
let property_decl_opt = obj_c_property_impl_decl_info.Clang_ast_t.opidi_property_decl in let property_decl_opt = obj_c_property_impl_decl_info.Clang_ast_t.opidi_property_decl in
match CAst_utils.get_decl_opt_with_decl_ref property_decl_opt with match CAst_utils.get_decl_opt_with_decl_ref property_decl_opt with
| Some ObjCPropertyDecl (_, _, obj_c_property_decl_info) -> | Some ObjCPropertyDecl (_, _, obj_c_property_decl_info) ->
let ivar_decl_ref = obj_c_property_decl_info.Clang_ast_t.opdi_ivar_decl in let process_accessor pointer =
(match CAst_utils.get_decl_opt_with_decl_ref ivar_decl_ref with (match CAst_utils.get_decl_opt_with_decl_ref pointer with
| Some ObjCIvarDecl (_, named_decl_info, _, _, _) -> | Some (ObjCMethodDecl _ as dec) ->
let field_name = CGeneral_utils.mk_class_field_name named_decl_info in process_method_decl ~set_objc_accessor_attr:true trans_unit_ctx tenv cg cfg
let process_accessor pointer ~getter = curr_class dec ~is_objc:true
(match CAst_utils.get_decl_opt_with_decl_ref pointer with | _ -> ()) in
| Some (ObjCMethodDecl (decl_info, _, _) as d) -> process_accessor obj_c_property_decl_info.Clang_ast_t.opdi_getter_method;
let source_range = decl_info.Clang_ast_t.di_source_range in process_accessor obj_c_property_decl_info.Clang_ast_t.opdi_setter_method
let loc =
CLocation.get_sil_location_from_range trans_unit_ctx source_range true in
let property_accessor =
if getter then
Some (ProcAttributes.Objc_getter field_name)
else
Some (ProcAttributes.Objc_setter field_name) in
let procname = CProcname.from_decl trans_unit_ctx d in
let attrs = { (ProcAttributes.default procname Config.Clang) with
loc = loc;
objc_accessor = property_accessor; } in
ignore (Cfg.create_proc_desc cfg attrs)
| _ -> ()) in
process_accessor obj_c_property_decl_info.Clang_ast_t.opdi_getter_method ~getter:true;
process_accessor obj_c_property_decl_info.Clang_ast_t.opdi_setter_method ~getter:false
| _ -> ())
| _ -> () | _ -> ()
let process_one_method_decl trans_unit_ctx tenv cg cfg curr_class dec = let process_one_method_decl trans_unit_ctx tenv cg cfg curr_class dec =
@ -125,7 +114,8 @@ struct
| ObjCMethodDecl _ -> | ObjCMethodDecl _ ->
process_method_decl trans_unit_ctx tenv cg cfg curr_class dec ~is_objc:true process_method_decl trans_unit_ctx tenv cg cfg curr_class dec ~is_objc:true
| ObjCPropertyImplDecl (_, obj_c_property_impl_decl_info) -> | ObjCPropertyImplDecl (_, obj_c_property_impl_decl_info) ->
process_property_implementation cfg trans_unit_ctx obj_c_property_impl_decl_info process_property_implementation trans_unit_ctx tenv cg cfg curr_class
obj_c_property_impl_decl_info
| EmptyDecl _ | EmptyDecl _
| ObjCIvarDecl _ | ObjCPropertyDecl _ -> () | ObjCIvarDecl _ | ObjCPropertyDecl _ -> ()
| _ -> | _ ->

@ -286,13 +286,6 @@ let get_objc_method_data obj_c_message_expr_info =
| `Class _ | `Class _
| `SuperClass -> (selector, pointer, MCStatic) | `SuperClass -> (selector, pointer, MCStatic)
let skip_property_accessor ms =
let open Clang_ast_t in
let pointer_to_property_opt = CMethod_signature.ms_get_pointer_to_property_opt ms in
match CAst_utils.get_decl_opt pointer_to_property_opt with
| Some (ObjCPropertyDecl _) -> true
| _ -> false
let get_formal_parameters tenv ms = let get_formal_parameters tenv ms =
let rec defined_parameters pl = let rec defined_parameters pl =
match pl with match pl with
@ -331,11 +324,11 @@ let sil_func_attributes_of_attributes attrs =
| _:: tl -> do_translation acc tl in | _:: tl -> do_translation acc tl in
do_translation [] attrs do_translation [] attrs
let should_create_procdesc cfg procname defined = let should_create_procdesc cfg procname defined set_objc_accessor_attr =
match Cfg.find_proc_desc_from_name cfg procname with match Cfg.find_proc_desc_from_name cfg procname with
| Some previous_procdesc -> | Some previous_procdesc ->
let is_defined_previous = Procdesc.is_defined previous_procdesc in let is_defined_previous = Procdesc.is_defined previous_procdesc in
if defined && (not is_defined_previous) then if (defined || set_objc_accessor_attr) && (not is_defined_previous) then
(Cfg.remove_proc_desc cfg (Procdesc.get_proc_name previous_procdesc); (Cfg.remove_proc_desc cfg (Procdesc.get_proc_name previous_procdesc);
true) true)
else false else false
@ -371,8 +364,25 @@ let get_const_args_indices ~shift args =
aux result tl in aux result tl in
aux [] args aux [] args
let get_objc_property_accessor ms =
let open Clang_ast_t in
match CAst_utils.get_decl_opt (CMethod_signature.ms_get_pointer_to_property_opt ms) with
| Some (ObjCPropertyDecl (_, _, obj_c_property_decl_info)) ->
let ivar_decl_ref = obj_c_property_decl_info.Clang_ast_t.opdi_ivar_decl in
(match CAst_utils.get_decl_opt_with_decl_ref ivar_decl_ref with
| Some ObjCIvarDecl (_, named_decl_info, _, _, _) ->
let field_name = CGeneral_utils.mk_class_field_name named_decl_info in
if CMethod_signature.ms_is_getter ms then
Some (ProcAttributes.Objc_getter field_name)
else if CMethod_signature.ms_is_setter ms then
Some (ProcAttributes.Objc_setter field_name)
else None
| _ -> None)
| _ -> None
(** Creates a procedure description. *) (** Creates a procedure description. *)
let create_local_procdesc trans_unit_ctx cfg tenv ms fbody captured is_objc_inst_method = let create_local_procdesc ?(set_objc_accessor_attr=false) trans_unit_ctx cfg tenv ms
fbody captured is_objc_inst_method =
let defined = not (Int.equal (List.length fbody) 0) in let defined = not (Int.equal (List.length fbody) 0) in
let proc_name = CMethod_signature.ms_get_name ms in let proc_name = CMethod_signature.ms_get_name ms in
let pname = Procname.to_string proc_name in let pname = Procname.to_string proc_name in
@ -397,35 +407,37 @@ let create_local_procdesc trans_unit_ctx cfg tenv ms fbody captured is_objc_inst
let loc_start = CLocation.get_sil_location_from_range trans_unit_ctx source_range true in let loc_start = CLocation.get_sil_location_from_range trans_unit_ctx source_range true in
let loc_exit = CLocation.get_sil_location_from_range trans_unit_ctx source_range false in let loc_exit = CLocation.get_sil_location_from_range trans_unit_ctx source_range false in
let ret_type = get_return_type tenv ms in let ret_type = get_return_type tenv ms in
if skip_property_accessor ms then () let objc_property_accessor =
else if set_objc_accessor_attr then get_objc_property_accessor ms
let procdesc = else None in
let proc_attributes = let procdesc =
{ (ProcAttributes.default proc_name Config.Clang) with let proc_attributes =
ProcAttributes.captured = captured_mangled; { (ProcAttributes.default proc_name Config.Clang) with
formals; ProcAttributes.captured = captured_mangled;
const_formals; formals;
func_attributes = attributes; const_formals;
is_defined = defined; func_attributes = attributes;
is_objc_instance_method = is_objc_inst_method; is_defined = defined;
is_cpp_instance_method = is_cpp_inst_method; is_objc_instance_method = is_objc_inst_method;
is_model = Config.models_mode; is_cpp_instance_method = is_cpp_inst_method;
loc = loc_start; is_model = Config.models_mode;
translation_unit = Some trans_unit_ctx.CFrontend_config.source_file; loc = loc_start;
method_annotation; objc_accessor = objc_property_accessor;
ret_type; translation_unit = Some trans_unit_ctx.CFrontend_config.source_file;
} in method_annotation;
Cfg.create_proc_desc cfg proc_attributes in ret_type;
if defined then } in
(if !Config.arc_mode then Cfg.create_proc_desc cfg proc_attributes in
Procdesc.set_flag procdesc Mleak_buckets.objc_arc_flag "true"; if defined then
let start_kind = Procdesc.Node.Start_node proc_name in (if !Config.arc_mode then
let start_node = Procdesc.create_node procdesc loc_start start_kind [] in Procdesc.set_flag procdesc Mleak_buckets.objc_arc_flag "true";
let exit_kind = Procdesc.Node.Exit_node proc_name in let start_kind = Procdesc.Node.Start_node proc_name in
let exit_node = Procdesc.create_node procdesc loc_exit exit_kind [] in let start_node = Procdesc.create_node procdesc loc_start start_kind [] in
Procdesc.set_start_node procdesc start_node; let exit_kind = Procdesc.Node.Exit_node proc_name in
Procdesc.set_exit_node procdesc exit_node) in let exit_node = Procdesc.create_node procdesc loc_exit exit_kind [] in
if should_create_procdesc cfg proc_name defined then Procdesc.set_start_node procdesc start_node;
Procdesc.set_exit_node procdesc exit_node) in
if should_create_procdesc cfg proc_name defined set_objc_accessor_attr then
(create_new_procdesc (); true) (create_new_procdesc (); true)
else false else false

@ -25,9 +25,10 @@ val equal_method_call_type : method_call_type -> method_call_type -> bool
val should_add_return_param : Typ.t -> is_objc_method:bool -> bool val should_add_return_param : Typ.t -> is_objc_method:bool -> bool
val create_local_procdesc : CFrontend_config.translation_unit_context -> Cfg.cfg -> Tenv.t -> val create_local_procdesc : ?set_objc_accessor_attr:bool ->
CMethod_signature.method_signature -> Clang_ast_t.stmt list -> (Pvar.t * Typ.t) list -> bool -> CFrontend_config.translation_unit_context -> Cfg.cfg -> Tenv.t ->
bool CMethod_signature.method_signature -> Clang_ast_t.stmt list -> (Pvar.t * Typ.t) list ->
bool -> bool
val create_external_procdesc : Cfg.cfg -> Procname.t -> bool -> (Typ.t * Typ.t list) option -> unit val create_external_procdesc : Cfg.cfg -> Procname.t -> bool -> (Typ.t * Typ.t list) option -> unit

@ -114,6 +114,7 @@ codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie3, 5, TAINTED_VALUE_R
codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie4, 5, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure testNSHTTPCookie4()] codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie4, 5, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure testNSHTTPCookie4()]
codetoanalyze/objc/errors/taint/viewController.m, ExampleDelegate_application:openURL:sourceApplication:annotation:, 7, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure application:openURL:sourceApplication:annotation:,start of procedure init,return from a call to VCA_init,start of procedure ExampleSanitizer(),Condition is false,return from a call to ExampleSanitizer,Condition is false,Condition is true] codetoanalyze/objc/errors/taint/viewController.m, ExampleDelegate_application:openURL:sourceApplication:annotation:, 7, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure application:openURL:sourceApplication:annotation:,start of procedure init,return from a call to VCA_init,start of procedure ExampleSanitizer(),Condition is false,return from a call to ExampleSanitizer,Condition is false,Condition is true]
codetoanalyze/objc/shared/annotations/nullable_annotations.m, User_otherUserName, 2, NULL_DEREFERENCE, [start of procedure otherUserName] codetoanalyze/objc/shared/annotations/nullable_annotations.m, User_otherUserName, 2, NULL_DEREFERENCE, [start of procedure otherUserName]
codetoanalyze/objc/shared/annotations/nullable_annotations.m, npe_property_nullable, 3, NULL_DEREFERENCE, [start of procedure npe_property_nullable()]
codetoanalyze/objc/shared/block/block-it.m, MyBlock_array, 3, RETURN_VALUE_IGNORED, [start of procedure array,Condition is true] codetoanalyze/objc/shared/block/block-it.m, MyBlock_array, 3, RETURN_VALUE_IGNORED, [start of procedure array,Condition is true]
codetoanalyze/objc/shared/block/block-it.m, __objc_anonymous_block_MyBlock_array______1, 5, UNINITIALIZED_VALUE, [start of procedure block,Condition is false] codetoanalyze/objc/shared/block/block-it.m, __objc_anonymous_block_MyBlock_array______1, 5, UNINITIALIZED_VALUE, [start of procedure block,Condition is false]
codetoanalyze/objc/shared/block/block-it.m, __objc_anonymous_block_MyBlock_array_trans______2, 4, UNINITIALIZED_VALUE, [start of procedure block,Condition is false] codetoanalyze/objc/shared/block/block-it.m, __objc_anonymous_block_MyBlock_array_trans______2, 4, UNINITIALIZED_VALUE, [start of procedure block,Condition is false]

@ -8,6 +8,12 @@
*/ */
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@interface Person : NSObject
@property(nullable, copy) Person* child;
@end
@interface User : NSObject @interface User : NSObject
- (nullable instancetype)initWithName:(nullable NSString*)name; - (nullable instancetype)initWithName:(nullable NSString*)name;
@ -45,4 +51,11 @@
User* ou = [self otherUser]; User* ou = [self otherUser];
return ou->_name; return ou->_name;
} }
NSDictionary* npe_property_nullable() {
Person* person = [Person new];
Person* child = person.child;
return @{ @"key" : child };
}
@end @end

@ -1,61 +1,80 @@
/* @generated */ /* @generated */
digraph iCFG { digraph iCFG {
"User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_1" [label="1: Start User_tellMeSomething\nFormals: self:class User*\nLocals: \nAnnotation: <_Nullable> User_tellMeSomething(<>) \n DECLARE_LOCALS(&return); [line 29]\n " color=yellow style=filled] "npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_1" [label="1: Start npe_property_nullable\nFormals: \nLocals: child:class Person* person:class Person* \n DECLARE_LOCALS(&return,&child,&person); [line 55]\n " color=yellow style=filled]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_1" -> "npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_5" ;
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_2" [label="2: Exit npe_property_nullable \n " color=yellow style=filled]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_3" [label="3: Return Stmt \n n$0=*&child:class Person* [line 58]\n n$1=_fun_NSString_stringWithUTF8String:(\"key\":char*) [line 58]\n n$2=_fun_NSDictionary_dictionaryWithObjects:forKeys:count:(n$0:struct objc_object*,n$1:struct objc_object*,0:struct objc_object*) [line 58]\n *&return:class NSDictionary*=n$2 [line 58]\n " shape="box"]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_3" -> "npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_2" ;
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_4" [label="4: DeclStmt \n n$3=*&person:class Person* [line 57]\n n$4=_fun_Person_child(n$3:class Person*) [line 57]\n *&child:class Person*=n$4 [line 57]\n " shape="box"]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_4" -> "npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_3" ;
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_5" [label="5: DeclStmt \n n$5=_fun___objc_alloc_no_fail(sizeof(class Person):unsigned long) [line 56]\n n$6=_fun_NSObject_init(n$5:class Person*) virtual [line 56]\n *&person:class Person*=n$6 [line 56]\n " shape="box"]
"npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_5" -> "npe_property_nullable.ba4461b16b55481ab8de5124734d2bf3_4" ;
"User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_1" [label="1: Start User_tellMeSomething\nFormals: self:class User*\nLocals: \nAnnotation: <_Nullable> User_tellMeSomething(<>) \n DECLARE_LOCALS(&return); [line 35]\n " color=yellow style=filled]
"User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_1" -> "User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_3" ; "User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_1" -> "User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_3" ;
"User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_2" [label="2: Exit User_tellMeSomething \n " color=yellow style=filled] "User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_2" [label="2: Exit User_tellMeSomething \n " color=yellow style=filled]
"User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_3" [label="3: Return Stmt \n n$1=_fun_NSString_stringWithUTF8String:(\"Hi\":char*) [line 30]\n *&return:class NSString*=n$1 [line 30]\n " shape="box"] "User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_3" [label="3: Return Stmt \n n$1=_fun_NSString_stringWithUTF8String:(\"Hi\":char*) [line 36]\n *&return:class NSString*=n$1 [line 36]\n " shape="box"]
"User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_3" -> "User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_2" ; "User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_3" -> "User_tellMeSomethinginstance.b54f02b8c304dfa023d23f9f4df4c2e1_2" ;
"User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_1" [label="1: Start User_tellMeSomethingNotNullable\nFormals: self:class User*\nLocals: \n DECLARE_LOCALS(&return); [line 33]\n " color=yellow style=filled] "User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_1" [label="1: Start User_tellMeSomethingNotNullable\nFormals: self:class User*\nLocals: \n DECLARE_LOCALS(&return); [line 39]\n " color=yellow style=filled]
"User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_1" -> "User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_3" ; "User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_1" -> "User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_3" ;
"User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_2" [label="2: Exit User_tellMeSomethingNotNullable \n " color=yellow style=filled] "User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_2" [label="2: Exit User_tellMeSomethingNotNullable \n " color=yellow style=filled]
"User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_3" [label="3: Return Stmt \n n$2=_fun_NSString_stringWithUTF8String:(\"Hi\":char*) [line 34]\n *&return:class NSString*=n$2 [line 34]\n " shape="box"] "User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_3" [label="3: Return Stmt \n n$2=_fun_NSString_stringWithUTF8String:(\"Hi\":char*) [line 40]\n *&return:class NSString*=n$2 [line 40]\n " shape="box"]
"User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_3" -> "User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_2" ; "User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_3" -> "User_tellMeSomethingNotNullableinstance.a40d0ee63f3aeb90706900a49136196b_2" ;
"User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_1" [label="1: Start User_otherUserName\nFormals: self:class User*\nLocals: ou:class User* \n DECLARE_LOCALS(&return,&ou); [line 44]\n " color=yellow style=filled] "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_1" [label="1: Start User_otherUserName\nFormals: self:class User*\nLocals: ou:class User* \n DECLARE_LOCALS(&return,&ou); [line 50]\n " color=yellow style=filled]
"User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_1" -> "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_4" ; "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_1" -> "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_4" ;
"User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_2" [label="2: Exit User_otherUserName \n " color=yellow style=filled] "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_2" [label="2: Exit User_otherUserName \n " color=yellow style=filled]
"User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_3" [label="3: Return Stmt \n n$4=*&ou:class User* [line 46]\n n$5=*n$4._name:class NSString* [line 46]\n *&return:class NSString*=n$5 [line 46]\n " shape="box"] "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_3" [label="3: Return Stmt \n n$4=*&ou:class User* [line 52]\n n$5=*n$4._name:class NSString* [line 52]\n *&return:class NSString*=n$5 [line 52]\n " shape="box"]
"User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_3" -> "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_2" ; "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_3" -> "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_2" ;
"User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_4" [label="4: DeclStmt \n n$6=*&self:class User* [line 45]\n n$7=_fun_User_otherUser(n$6:class User*) virtual [line 45]\n *&ou:class User*=n$7 [line 45]\n " shape="box"] "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_4" [label="4: DeclStmt \n n$6=*&self:class User* [line 51]\n n$7=_fun_User_otherUser(n$6:class User*) virtual [line 51]\n *&ou:class User*=n$7 [line 51]\n " shape="box"]
"User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_4" -> "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_3" ; "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_4" -> "User_otherUserNameinstance.d96d9ea375a633021df5bfc33fa4c63c_3" ;
"User_initWithName:instance.9593030a12738a1c563396f127eaaa37_1" [label="1: Start User_initWithName:\nFormals: self:class User* name:class NSString*\nLocals: \nAnnotation: <_Nullable> User_initWithName:(<> <_Nullable>) \n DECLARE_LOCALS(&return); [line 25]\n " color=yellow style=filled] "User_initWithName:instance.9593030a12738a1c563396f127eaaa37_1" [label="1: Start User_initWithName:\nFormals: self:class User* name:class NSString*\nLocals: \nAnnotation: <_Nullable> User_initWithName:(<> <_Nullable>) \n DECLARE_LOCALS(&return); [line 31]\n " color=yellow style=filled]
"User_initWithName:instance.9593030a12738a1c563396f127eaaa37_1" -> "User_initWithName:instance.9593030a12738a1c563396f127eaaa37_3" ; "User_initWithName:instance.9593030a12738a1c563396f127eaaa37_1" -> "User_initWithName:instance.9593030a12738a1c563396f127eaaa37_3" ;
"User_initWithName:instance.9593030a12738a1c563396f127eaaa37_2" [label="2: Exit User_initWithName: \n " color=yellow style=filled] "User_initWithName:instance.9593030a12738a1c563396f127eaaa37_2" [label="2: Exit User_initWithName: \n " color=yellow style=filled]
"User_initWithName:instance.9593030a12738a1c563396f127eaaa37_3" [label="3: Return Stmt \n n$0=*&self:class User* [line 26]\n *&return:struct objc_object*=n$0 [line 26]\n " shape="box"] "User_initWithName:instance.9593030a12738a1c563396f127eaaa37_3" [label="3: Return Stmt \n n$0=*&self:class User* [line 32]\n *&return:struct objc_object*=n$0 [line 32]\n " shape="box"]
"User_initWithName:instance.9593030a12738a1c563396f127eaaa37_3" -> "User_initWithName:instance.9593030a12738a1c563396f127eaaa37_2" ; "User_initWithName:instance.9593030a12738a1c563396f127eaaa37_3" -> "User_initWithName:instance.9593030a12738a1c563396f127eaaa37_2" ;
"User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_1" [label="1: Start User_tellMeSomething:and:and:and:\nFormals: self:class User* s1:class NSString* s2:class NSString* s3:class NSString* s4:class NSString*\nLocals: \nAnnotation: <> User_tellMeSomething:and:and:and:(<> <> <> <_Nullable> <>) \n DECLARE_LOCALS(&return); [line 37]\n " color=yellow style=filled] "User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_1" [label="1: Start User_tellMeSomething:and:and:and:\nFormals: self:class User* s1:class NSString* s2:class NSString* s3:class NSString* s4:class NSString*\nLocals: \nAnnotation: <> User_tellMeSomething:and:and:and:(<> <> <> <_Nullable> <>) \n DECLARE_LOCALS(&return); [line 43]\n " color=yellow style=filled]
"User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_1" -> "User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_3" ; "User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_1" -> "User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_3" ;
"User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_2" [label="2: Exit User_tellMeSomething:and:and:and: \n " color=yellow style=filled] "User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_2" [label="2: Exit User_tellMeSomething:and:and:and: \n " color=yellow style=filled]
"User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_3" [label="3: Return Stmt \n n$3=_fun_NSString_stringWithUTF8String:(\"Hi\":char*) [line 41]\n *&return:class NSString*=n$3 [line 41]\n " shape="box"] "User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_3" [label="3: Return Stmt \n n$3=_fun_NSString_stringWithUTF8String:(\"Hi\":char*) [line 47]\n *&return:class NSString*=n$3 [line 47]\n " shape="box"]
"User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_3" -> "User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_2" ; "User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_3" -> "User_tellMeSomething:and:and:and:instance.12fb98968dde54a144a6102e598bee03_2" ;

Loading…
Cancel
Save