diff --git a/infer/src/backend/rearrange.ml b/infer/src/backend/rearrange.ml index 4407f1967..a693a2294 100644 --- a/infer/src/backend/rearrange.ml +++ b/infer/src/backend/rearrange.ml @@ -1281,74 +1281,89 @@ let rec iter_rearrange end; res -let is_weak_captured_var pdesc pvar = +let is_weak_captured_var pdesc var_name = let pname = Procdesc.get_proc_name pdesc in match pname with | Block _ -> let is_weak_captured (var, typ) = match typ with | Typ.Tptr (_, Pk_objc_weak) -> - Mangled.equal (Pvar.get_name pvar) var + String.equal var_name (Mangled.to_string var) | _ -> false in List.exists ~f:is_weak_captured (Procdesc.get_captured pdesc) | _ -> false +let var_has_annotation ?(check_weak_captured_var=false) pdesc is_annotation pvar = + let is_weak_captured_var = is_weak_captured_var pdesc (Pvar.to_string pvar) in + let ann_sig = Models.get_modelled_annotated_signature (Specs.pdesc_resolve_attributes pdesc) in + AnnotatedSignature.param_has_annot is_annotation pvar ann_sig || + (check_weak_captured_var && is_weak_captured_var) + +let attr_has_annot is_annotation tenv prop exp = + let attr_has_annot = function + | Sil.Apred ((Aretval (pname, ret_attr) | Aundef (pname, ret_attr, _, _)), _) + when is_annotation ret_attr -> + Some (Typ.Procname.to_string pname) + | _ -> None in + try List.find_map ~f:attr_has_annot (Attribute.get_for_exp tenv prop exp) + with Not_found -> None + +let is_strexp_pt_fld_with_annot tenv obj_str is_annotation typ deref_exp (fld, strexp) = + let lookup = Tenv.lookup tenv in + let fld_has_annot fld = + match Typ.Struct.get_field_type_and_annotation ~lookup fld typ with + | Some (_, annot) -> is_annotation annot + | _ -> false in + match strexp with + | Sil.Eexp (Exp.Var _ as exp, _) when Exp.equal exp deref_exp -> + let has_annot = fld_has_annot fld in + if has_annot then + obj_str := Some (Ident.fieldname_to_simplified_string fld); + has_annot + | _ -> true + +(* This returns true if the exp is pointed to only by fields or parameters with a given + annotation. In that case it also returns a string representation of the annotation + recipient. *) +let is_only_pt_by_fld_or_param_with_annot + ?(check_weak_captured_var=false) pdesc tenv prop deref_exp is_annotation = + let obj_str = ref None in + let is_pt_by_fld_or_param_with_annot hpred = + match hpred with + | Sil.Hpointsto (Exp.Lvar pvar, Sil.Eexp (Exp.Var _ as exp, _), _) + when Exp.equal exp deref_exp -> + let var_has_annotation = + var_has_annotation ~check_weak_captured_var pdesc is_annotation pvar in + if var_has_annotation then obj_str := Some (Pvar.to_string pvar); + let procname_str_opt = attr_has_annot is_annotation tenv prop exp in + if Option.is_some procname_str_opt then obj_str := procname_str_opt; + (* it's ok for a local with no annotation to point to deref_exp *) + var_has_annotation || Option.is_some procname_str_opt || Pvar.is_local pvar + | Sil.Hpointsto (_, Sil.Estruct (flds, _), Exp.Sizeof (typ, _, _)) -> + List.for_all ~f:(is_strexp_pt_fld_with_annot tenv obj_str is_annotation typ deref_exp) flds + | _ -> true in + if List.for_all ~f:is_pt_by_fld_or_param_with_annot prop.Prop.sigma && !obj_str <> None + then !obj_str + else None + +let is_only_pt_by_fld_or_param_nullable pdesc tenv prop deref_exp = + is_only_pt_by_fld_or_param_with_annot ~check_weak_captured_var:true + pdesc tenv prop deref_exp Annotations.ia_is_nullable + +let is_only_pt_by_fld_or_param_nonnull pdesc tenv prop deref_exp = + Option.is_some + (is_only_pt_by_fld_or_param_with_annot pdesc tenv prop deref_exp Annotations.ia_is_nonnull) (** Check for dereference errors: dereferencing 0, a freed value, or an undefined value *) let check_dereference_error tenv pdesc (prop : Prop.normal Prop.t) lexp loc = - let lookup = Tenv.lookup tenv in - let nullable_obj_str = ref None in - let nullable_str_is_weak_captured_var = ref false in - (* return true if deref_exp is only pointed to by fields/params with @Nullable annotations *) - let is_only_pt_by_nullable_fld_or_param deref_exp = - let ann_sig = Models.get_modelled_annotated_signature (Specs.pdesc_resolve_attributes pdesc) in - List.for_all - ~f:(fun hpred -> - match hpred with - | Sil.Hpointsto (Exp.Lvar pvar, Sil.Eexp (Exp.Var _ as exp, _), _) - when Exp.equal exp deref_exp -> - let is_weak_captured_var = is_weak_captured_var pdesc pvar in - let is_nullable = - if AnnotatedSignature.param_is_nullable pvar ann_sig || is_weak_captured_var - then - begin - nullable_obj_str := Some (Pvar.to_string pvar); - nullable_str_is_weak_captured_var := is_weak_captured_var; - true - end - else - let is_nullable_attr = function - | Sil.Apred ((Aretval (pname, ret_attr) | Aundef (pname, ret_attr, _, _)), _) - when Annotations.ia_is_nullable ret_attr -> - nullable_obj_str := Some (Typ.Procname.to_string pname); - true - | _ -> false in - List.exists ~f:is_nullable_attr (Attribute.get_for_exp tenv prop exp) in - (* it's ok for a non-nullable local to point to deref_exp *) - is_nullable || Pvar.is_local pvar - | Sil.Hpointsto (_, Sil.Estruct (flds, _), Exp.Sizeof (typ, _, _)) -> - let fld_is_nullable fld = - match Typ.Struct.get_field_type_and_annotation ~lookup fld typ with - | Some (_, annot) -> Annotations.ia_is_nullable annot - | _ -> false in - let is_strexp_pt_by_nullable_fld (fld, strexp) = - match strexp with - | Sil.Eexp (Exp.Var _ as exp, _) when Exp.equal exp deref_exp -> - let is_nullable = fld_is_nullable fld in - if is_nullable then - nullable_obj_str := Some (Ident.fieldname_to_simplified_string fld); - is_nullable - | _ -> true in - List.for_all ~f:is_strexp_pt_by_nullable_fld flds - | _ -> true) - prop.Prop.sigma && - !nullable_obj_str <> None in let root = Exp.root_of_lexp lexp in + let nullable_var_opt = + is_only_pt_by_fld_or_param_nullable pdesc tenv prop root in let is_deref_of_nullable = let is_definitely_non_null exp prop = Prover.check_disequal tenv prop exp Exp.zero in Config.report_nullable_inconsistency && not (is_definitely_non_null root prop) - && is_only_pt_by_nullable_fld_or_param root in + && Option.is_some nullable_var_opt in let relevant_attributes_getters = [ Attribute.get_resource tenv; Attribute.get_undef tenv; @@ -1371,9 +1386,9 @@ let check_dereference_error tenv pdesc (prop : Prop.normal Prop.t) lexp loc = begin let deref_str = if is_deref_of_nullable then - match !nullable_obj_str with + match nullable_var_opt with | Some str -> - if !nullable_str_is_weak_captured_var then + if is_weak_captured_var pdesc str then Localise.deref_str_weak_variable_in_block None str else Localise.deref_str_nullable None str | None -> Localise.deref_str_nullable None "" diff --git a/infer/src/backend/rearrange.mli b/infer/src/backend/rearrange.mli index 4fe127e18..1e4c3fbad 100644 --- a/infer/src/backend/rearrange.mli +++ b/infer/src/backend/rearrange.mli @@ -14,6 +14,13 @@ open! IStd exception ARRAY_ACCESS +val is_only_pt_by_fld_or_param_with_annot : + ?check_weak_captured_var:bool -> Procdesc.t -> Tenv.t -> Prop.normal Prop.t -> + Exp.t -> (Annot.Item.t -> bool) -> string option + +val is_only_pt_by_fld_or_param_nonnull : Procdesc.t -> Tenv.t -> Prop.normal Prop.t -> + Exp.t -> bool + (** Check for dereference errors: dereferencing 0, a freed value, or an undefined value *) val check_dereference_error : Tenv.t -> Procdesc.t -> Prop.normal Prop.t -> Exp.t -> Location.t -> unit diff --git a/infer/src/backend/symExec.ml b/infer/src/backend/symExec.ml index 0415680f8..45349a3ef 100644 --- a/infer/src/backend/symExec.ml +++ b/infer/src/backend/symExec.ml @@ -766,7 +766,8 @@ let handle_objc_instance_method_call_or_skip pdesc tenv actual_pars path callee_ else match force_objc_init_return_nil pdesc callee_pname tenv ret_id pre path receiver with | [] -> - if !Config.footprint && Option.is_none (Attribute.get_undef tenv pre receiver) then + if !Config.footprint && Option.is_none (Attribute.get_undef tenv pre receiver) && + not (Rearrange.is_only_pt_by_fld_or_param_nonnull pdesc tenv pre receiver) then let res_null = (* returns: (objc_null(res) /\ receiver=0) or an empty list of results *) let pre_with_attr_or_null = add_objc_null_attribute_or_nullify_result pre in let propset = prune_ne tenv ~positive:false receiver Exp.zero pre_with_attr_or_null in @@ -1195,7 +1196,8 @@ let rec sym_exec tenv current_pdesc _instr (prop_: Prop.normal Prop.t) path ) | Sil.Call (ret_id, fun_exp, actual_params, loc, call_flags) -> (* Call via function pointer *) let (prop_r, n_actual_params) = normalize_params tenv current_pname prop_ actual_params in - if call_flags.CallFlags.cf_is_objc_block then + if call_flags.CallFlags.cf_is_objc_block && + not (Rearrange.is_only_pt_by_fld_or_param_nonnull current_pdesc tenv prop_r fun_exp) then Rearrange.check_call_to_objc_block_error tenv current_pdesc prop_r fun_exp loc; Rearrange.check_dereference_error tenv current_pdesc prop_r fun_exp loc; if call_flags.CallFlags.cf_noreturn then begin diff --git a/infer/src/checkers/annotations.mli b/infer/src/checkers/annotations.mli index 791ffb0da..66577d1dc 100644 --- a/infer/src/checkers/annotations.mli +++ b/infer/src/checkers/annotations.mli @@ -15,6 +15,7 @@ val any_thread : string val expensive : string val no_allocation : string val nullable : string +val nonnull : string val on_bind : string val performance_critical : string val present : string diff --git a/infer/src/clang/cAst_utils.ml b/infer/src/clang/cAst_utils.ml index 791370f5f..2da7ce4ac 100644 --- a/infer/src/clang/cAst_utils.ml +++ b/infer/src/clang/cAst_utils.ml @@ -166,6 +166,7 @@ let sil_annot_of_type type_ptr = match get_type type_ptr with | Some AttributedType (_, attr_info) -> if attr_info.ati_attr_kind = `Nullable then Some Annotations.nullable + else if attr_info.ati_attr_kind = `Nonnull then Some Annotations.nonnull (* other annotations go here *) else None | _ -> None in diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 245ba7e29..000725e31 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -143,16 +143,6 @@ let build_method_signature trans_unit_ctx tenv decl_info procname function_metho procname parameters tp attributes source_range is_instance_method ~is_cpp_virtual:is_cpp_virtual lang parent_pointer pointer_to_property_opt return_param_type_opt -let get_assume_not_null_calls param_decls = - let do_one_param decl = match decl with - | Clang_ast_t.ParmVarDecl (decl_info, name, qt, _) - when CAst_utils.is_type_nonnull qt.Clang_ast_t.qt_type_ptr -> - let assume_call = Ast_expressions.create_assume_not_null_call - decl_info name qt.Clang_ast_t.qt_type_ptr in - [(`ClangStmt assume_call)] - | _ -> [] in - List.concat_map ~f:do_one_param param_decls - let get_init_list_instrs method_decl_info = let create_custom_instr construct_instr = `CXXConstructorInit construct_instr in List.map ~f:create_custom_instr method_decl_info.Clang_ast_t.xmdi_cxx_ctor_initializers @@ -164,8 +154,7 @@ let method_signature_of_decl trans_unit_ctx tenv meth_decl block_data_opt = let func_decl = Func_decl_info (fdi, qt.Clang_ast_t.qt_type_ptr) in let procname = CProcname.from_decl trans_unit_ctx ~tenv meth_decl in let ms = build_method_signature trans_unit_ctx tenv decl_info procname func_decl None None in - let extra_instrs = get_assume_not_null_calls fdi.Clang_ast_t.fdi_parameters in - ms, fdi.Clang_ast_t.fdi_body, extra_instrs + ms, fdi.Clang_ast_t.fdi_body, [] | CXXMethodDecl (decl_info, _, qt, fdi, mdi), _ | CXXConstructorDecl (decl_info, _, qt, fdi, mdi), _ | CXXConversionDecl (decl_info, _, qt, fdi, mdi), _ @@ -176,9 +165,8 @@ let method_signature_of_decl trans_unit_ctx tenv meth_decl block_data_opt = let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in let ms = build_method_signature trans_unit_ctx tenv decl_info procname method_decl parent_pointer None in - let non_null_instrs = get_assume_not_null_calls fdi.Clang_ast_t.fdi_parameters in let init_list_instrs = get_init_list_instrs mdi in (* it will be empty for methods *) - ms, fdi.Clang_ast_t.fdi_body, (init_list_instrs @ non_null_instrs) + ms, fdi.Clang_ast_t.fdi_body, init_list_instrs | ObjCMethodDecl (decl_info, _, mdi), _ -> let procname = CProcname.from_decl trans_unit_ctx ~tenv meth_decl in let parent_ptr = Option.value_exn decl_info.di_parent_pointer in @@ -190,13 +178,11 @@ let method_signature_of_decl trans_unit_ctx tenv meth_decl block_data_opt = | None -> None in let ms = build_method_signature trans_unit_ctx tenv decl_info procname method_decl parent_pointer pointer_to_property_opt in - let extra_instrs = get_assume_not_null_calls mdi.omdi_parameters in - ms, mdi.omdi_body, extra_instrs + ms, mdi.omdi_body, [] | BlockDecl (decl_info, bdi), Some (outer_context, tp, procname, _) -> let func_decl = Block_decl_info (bdi, tp, outer_context) in let ms = build_method_signature trans_unit_ctx tenv decl_info procname func_decl None None in - let extra_instrs = get_assume_not_null_calls bdi.bdi_parameters in - ms, bdi.bdi_body, extra_instrs + ms, bdi.bdi_body, [] | _ -> raise Invalid_declaration let method_signature_of_pointer trans_unit_ctx tenv pointer = diff --git a/infer/src/eradicate/AnnotatedSignature.ml b/infer/src/eradicate/AnnotatedSignature.ml index a9d5b2e33..2043c4cc8 100644 --- a/infer/src/eradicate/AnnotatedSignature.ml +++ b/infer/src/eradicate/AnnotatedSignature.ml @@ -50,6 +50,12 @@ let param_is_nullable pvar ann_sig = Mangled.equal param (Pvar.get_name pvar) && Annotations.ia_is_nullable annot) ann_sig.params +let param_has_annot predicate pvar ann_sig = + List.exists + ~f:(fun (param, param_annot, _) -> + Mangled.equal param (Pvar.get_name pvar) && predicate param_annot) + ann_sig.params + let pp proc_name fmt annotated_signature = let pp_ia fmt ia = if ia <> [] then F.fprintf fmt "%a " Annot.Item.pp ia in let pp_annotated_param fmt (p, ia, t) = diff --git a/infer/src/eradicate/AnnotatedSignature.mli b/infer/src/eradicate/AnnotatedSignature.mli index 5f30931dc..4ca07f98f 100644 --- a/infer/src/eradicate/AnnotatedSignature.mli +++ b/infer/src/eradicate/AnnotatedSignature.mli @@ -28,6 +28,9 @@ val is_anonymous_inner_class_wrapper : t -> Typ.Procname.t -> bool (** Check if the given parameter has a Nullable annotation in the given signature *) val param_is_nullable : Pvar.t -> t -> bool +(** Check if the given parameter has an annotation in the given signature *) +val param_has_annot : (Annot.Item.t -> bool) -> Pvar.t -> t -> bool + (** Mark the return of the method_annotation with the given annotation. *) val method_annotation_mark_return : annotation -> Annot.Method.t -> Annot.Method.t diff --git a/infer/tests/codetoanalyze/objc/errors/Makefile b/infer/tests/codetoanalyze/objc/errors/Makefile index 74a5f55cd..d4b819a56 100644 --- a/infer/tests/codetoanalyze/objc/errors/Makefile +++ b/infer/tests/codetoanalyze/objc/errors/Makefile @@ -53,6 +53,7 @@ SOURCES_DEFAULT = \ shared/protocol_procdesc/main.c \ shared/annotations/nullable_annotations.m \ shared/annotations/nullable_annotations_fields.m \ + shared/annotations/nonnull_annotations.m \ taint/sources.m \ taint/viewController.m \ diff --git a/infer/tests/codetoanalyze/objc/errors/issues.exp b/infer/tests/codetoanalyze/objc/errors/issues.exp index dfa634a43..b64419653 100644 --- a/infer/tests/codetoanalyze/objc/errors/issues.exp +++ b/infer/tests/codetoanalyze/objc/errors/issues.exp @@ -98,6 +98,7 @@ codetoanalyze/objc/errors/npe/Fraction.m, test_virtual_call, 7, NULL_DEREFERENCE codetoanalyze/objc/errors/npe/NPD_core_foundation.m, NullDeref_createCloseCrossGlyphNoLeak:, 5, Assert_failure, [start of procedure createCloseCrossGlyphNoLeak:] codetoanalyze/objc/errors/npe/NPD_core_foundation.m, NullDeref_layoutSubviews, 4, Assert_failure, [start of procedure layoutSubviews] codetoanalyze/objc/errors/npe/NPD_core_foundation.m, NullDeref_measureFrameSizeForTextNoLeak, 4, Assert_failure, [start of procedure measureFrameSizeForTextNoLeak,Condition is true] +codetoanalyze/objc/errors/npe/NPD_core_foundation.m, NullDeref_test2, 2, Assert_failure, [start of procedure test2] codetoanalyze/objc/errors/npe/No_null_from_array.m, No_null_from_array_collectAvailableMaps, 5, RETURN_VALUE_IGNORED, [start of procedure collectAvailableMaps] codetoanalyze/objc/errors/npe/Npe_with_equal_names.m, EqualNamesTest, 3, NULL_DEREFERENCE, [start of procedure EqualNamesTest(),start of procedure meth,return from a call to EqualNamesA_meth] codetoanalyze/objc/errors/npe/Npe_with_equal_names.m, EqualNamesTest2, 2, UNINITIALIZED_VALUE, [start of procedure EqualNamesTest2(),start of procedure meth,return from a call to EqualNamesA_meth] @@ -113,6 +114,8 @@ codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie2, 5, TAINTED_VALUE_R codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie3, 5, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure testNSHTTPCookie3()] 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/shared/annotations/nonnull_annotations.m, A_test1:, 2, PARAMETER_NOT_NULL_CHECKED, [start of procedure test1:,Message child with receiver nil returns nil.] +codetoanalyze/objc/shared/annotations/nonnull_annotations.m, A_test3:, 1, PARAMETER_NOT_NULL_CHECKED, [start of procedure test3:] 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/annotations/nullable_annotations_fields.m, A_nullable_field, 3, NULL_DEREFERENCE, [start of procedure nullable_field] @@ -129,5 +132,7 @@ codetoanalyze/objc/shared/memory_leaks_benchmark/MemoryLeakExample.m, MemoryLeak codetoanalyze/objc/shared/memory_leaks_benchmark/MemoryLeakExample.m, MemoryLeakExample_regularLeak, 3, MEMORY_LEAK, [start of procedure regularLeak] codetoanalyze/objc/shared/memory_leaks_benchmark/MemoryLeakExample.m, MemoryLeakExample_test, 3, MEMORY_LEAK, [start of procedure test] codetoanalyze/objc/shared/memory_leaks_benchmark/MemoryLeakExample.m, MemoryLeakExample_test1:, 1, MEMORY_LEAK, [start of procedure test1:] +codetoanalyze/objc/shared/memory_leaks_benchmark/MemoryLeakExample.m, MemoryLeakExample_test1NoLeak, 2, Assert_failure, [start of procedure test1NoLeak] codetoanalyze/objc/shared/memory_leaks_benchmark/MemoryLeakExample.m, MemoryLeakExample_test2:, 1, MEMORY_LEAK, [start of procedure test2:] +codetoanalyze/objc/shared/memory_leaks_benchmark/MemoryLeakExample.m, MemoryLeakExample_test2NoLeak, 2, Assert_failure, [start of procedure test2NoLeak] codetoanalyze/objc/shared/npe/Nonnull_attribute_example.m, NonnullC_initWithCoder:and:, 2, UNINITIALIZED_VALUE, [start of procedure initWithCoder:and:,start of procedure getA,return from a call to NonnullA_getA] diff --git a/infer/tests/codetoanalyze/objc/frontend/noarc/Makefile b/infer/tests/codetoanalyze/objc/frontend/noarc/Makefile index 87062881b..b74b3f4ea 100644 --- a/infer/tests/codetoanalyze/objc/frontend/noarc/Makefile +++ b/infer/tests/codetoanalyze/objc/frontend/noarc/Makefile @@ -67,5 +67,6 @@ SOURCES = \ ../vardecl/aclass_2.m \ ../vardecl/last_af.m \ ../shared/annotations/nullable_annotations.m \ + ../shared/annotations/nonnull_annotations.m \ include $(TESTS_DIR)/clang-frontend.make diff --git a/infer/tests/codetoanalyze/objc/shared/annotations/nonnull_annotations.m b/infer/tests/codetoanalyze/objc/shared/annotations/nonnull_annotations.m new file mode 100644 index 000000000..e12905e87 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/shared/annotations/nonnull_annotations.m @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#import + +@interface A : NSObject + +@property A* child; + +@end + +@implementation A { + int x; +} + +- (instancetype)init { + return self; +} + +- (int)test1:(A*)a { + A* aa = [a child]; + return aa->x; +} + +- (int)test2:(nonnull A*)a { + A* aa = [a child]; + return aa->x; +} + +- (int)test3:(void (^)(NSString*))successBlock { + successBlock(@"Yay"); + return 0; +} + +- (int)test4:(void (^_Nonnull)(NSString*))successBlock { + successBlock(@"Yay"); + return 0; +} + +@end diff --git a/infer/tests/codetoanalyze/objc/shared/annotations/nonnull_annotations.m.dot b/infer/tests/codetoanalyze/objc/shared/annotations/nonnull_annotations.m.dot new file mode 100644 index 000000000..e7239d54f --- /dev/null +++ b/infer/tests/codetoanalyze/objc/shared/annotations/nonnull_annotations.m.dot @@ -0,0 +1,74 @@ +/* @generated */ +digraph iCFG { +"init#A#instance.eee79aaaddd644404e17691a7e7d809a_1" [label="1: Start A_init\nFormals: self:class A*\nLocals: \n DECLARE_LOCALS(&return); [line 21]\n " color=yellow style=filled] + + + "init#A#instance.eee79aaaddd644404e17691a7e7d809a_1" -> "init#A#instance.eee79aaaddd644404e17691a7e7d809a_3" ; +"init#A#instance.eee79aaaddd644404e17691a7e7d809a_2" [label="2: Exit A_init \n " color=yellow style=filled] + + +"init#A#instance.eee79aaaddd644404e17691a7e7d809a_3" [label="3: Return Stmt \n n$0=*&self:class A* [line 22]\n *&return:struct objc_object*=n$0 [line 22]\n " shape="box"] + + + "init#A#instance.eee79aaaddd644404e17691a7e7d809a_3" -> "init#A#instance.eee79aaaddd644404e17691a7e7d809a_2" ; +"test1:#A#instance.ebd5eea0b404af619c50927f18bab354_1" [label="1: Start A_test1:\nFormals: self:class A* a:class A*\nLocals: aa:class A* \n DECLARE_LOCALS(&return,&aa); [line 25]\n " color=yellow style=filled] + + + "test1:#A#instance.ebd5eea0b404af619c50927f18bab354_1" -> "test1:#A#instance.ebd5eea0b404af619c50927f18bab354_4" ; +"test1:#A#instance.ebd5eea0b404af619c50927f18bab354_2" [label="2: Exit A_test1: \n " color=yellow style=filled] + + +"test1:#A#instance.ebd5eea0b404af619c50927f18bab354_3" [label="3: Return Stmt \n n$1=*&aa:class A* [line 27]\n n$2=*n$1.x:int [line 27]\n *&return:int=n$2 [line 27]\n " shape="box"] + + + "test1:#A#instance.ebd5eea0b404af619c50927f18bab354_3" -> "test1:#A#instance.ebd5eea0b404af619c50927f18bab354_2" ; +"test1:#A#instance.ebd5eea0b404af619c50927f18bab354_4" [label="4: DeclStmt \n n$3=*&a:class A* [line 26]\n n$4=_fun_A_child(n$3:class A*) [line 26]\n *&aa:class A*=n$4 [line 26]\n " shape="box"] + + + "test1:#A#instance.ebd5eea0b404af619c50927f18bab354_4" -> "test1:#A#instance.ebd5eea0b404af619c50927f18bab354_3" ; +"test2:#A#instance.da747e16db8f3c52e20363adcaf73615_1" [label="1: Start A_test2:\nFormals: self:class A* a:class A*\nLocals: aa:class A*\nAnnotation: <> A_test2:(<> <_Nonnull>) \n DECLARE_LOCALS(&return,&aa); [line 30]\n " color=yellow style=filled] + + + "test2:#A#instance.da747e16db8f3c52e20363adcaf73615_1" -> "test2:#A#instance.da747e16db8f3c52e20363adcaf73615_4" ; +"test2:#A#instance.da747e16db8f3c52e20363adcaf73615_2" [label="2: Exit A_test2: \n " color=yellow style=filled] + + +"test2:#A#instance.da747e16db8f3c52e20363adcaf73615_3" [label="3: Return Stmt \n n$5=*&aa:class A* [line 32]\n n$6=*n$5.x:int [line 32]\n *&return:int=n$6 [line 32]\n " shape="box"] + + + "test2:#A#instance.da747e16db8f3c52e20363adcaf73615_3" -> "test2:#A#instance.da747e16db8f3c52e20363adcaf73615_2" ; +"test2:#A#instance.da747e16db8f3c52e20363adcaf73615_4" [label="4: DeclStmt \n n$7=*&a:class A* [line 31]\n n$8=_fun_A_child(n$7:class A*) [line 31]\n *&aa:class A*=n$8 [line 31]\n " shape="box"] + + + "test2:#A#instance.da747e16db8f3c52e20363adcaf73615_4" -> "test2:#A#instance.da747e16db8f3c52e20363adcaf73615_3" ; +"test3:#A#instance.28bc2df8df797b21818dc2037239f326_1" [label="1: Start A_test3:\nFormals: self:class A* successBlock:_fn_(*)\nLocals: \n DECLARE_LOCALS(&return); [line 35]\n " color=yellow style=filled] + + + "test3:#A#instance.28bc2df8df797b21818dc2037239f326_1" -> "test3:#A#instance.28bc2df8df797b21818dc2037239f326_4" ; +"test3:#A#instance.28bc2df8df797b21818dc2037239f326_2" [label="2: Exit A_test3: \n " color=yellow style=filled] + + +"test3:#A#instance.28bc2df8df797b21818dc2037239f326_3" [label="3: Return Stmt \n *&return:int=0 [line 37]\n " shape="box"] + + + "test3:#A#instance.28bc2df8df797b21818dc2037239f326_3" -> "test3:#A#instance.28bc2df8df797b21818dc2037239f326_2" ; +"test3:#A#instance.28bc2df8df797b21818dc2037239f326_4" [label="4: Call n$9 \n n$9=*&successBlock:_fn_(*) [line 36]\n n$10=_fun_NSString_stringWithUTF8String:(\"Yay\":char*) [line 36]\n n$9(n$10:class NSString*) [line 36]\n " shape="box"] + + + "test3:#A#instance.28bc2df8df797b21818dc2037239f326_4" -> "test3:#A#instance.28bc2df8df797b21818dc2037239f326_3" ; +"test4:#A#instance.718a300d6fa63609a70f22221a548ee5_1" [label="1: Start A_test4:\nFormals: self:class A* successBlock:_fn_(*)\nLocals: \nAnnotation: <> A_test4:(<> <_Nonnull>) \n DECLARE_LOCALS(&return); [line 40]\n " color=yellow style=filled] + + + "test4:#A#instance.718a300d6fa63609a70f22221a548ee5_1" -> "test4:#A#instance.718a300d6fa63609a70f22221a548ee5_4" ; +"test4:#A#instance.718a300d6fa63609a70f22221a548ee5_2" [label="2: Exit A_test4: \n " color=yellow style=filled] + + +"test4:#A#instance.718a300d6fa63609a70f22221a548ee5_3" [label="3: Return Stmt \n *&return:int=0 [line 42]\n " shape="box"] + + + "test4:#A#instance.718a300d6fa63609a70f22221a548ee5_3" -> "test4:#A#instance.718a300d6fa63609a70f22221a548ee5_2" ; +"test4:#A#instance.718a300d6fa63609a70f22221a548ee5_4" [label="4: Call n$11 \n n$11=*&successBlock:_fn_(*) [line 41]\n n$12=_fun_NSString_stringWithUTF8String:(\"Yay\":char*) [line 41]\n n$11(n$12:class NSString*) [line 41]\n " shape="box"] + + + "test4:#A#instance.718a300d6fa63609a70f22221a548ee5_4" -> "test4:#A#instance.718a300d6fa63609a70f22221a548ee5_3" ; +} diff --git a/infer/tests/codetoanalyze/objc/shared/npe/Nonnull_attribute_example.m.dot b/infer/tests/codetoanalyze/objc/shared/npe/Nonnull_attribute_example.m.dot index 86b32f3a1..d59236db8 100644 --- a/infer/tests/codetoanalyze/objc/shared/npe/Nonnull_attribute_example.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/npe/Nonnull_attribute_example.m.dot @@ -1,9 +1,9 @@ /* @generated */ digraph iCFG { -"NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_1" [label="1: Start NonnullAtrributeTest\nFormals: callback:_fn_(*)\nLocals: \n DECLARE_LOCALS(&return); [line 46]\n " color=yellow style=filled] +"NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_1" [label="1: Start NonnullAtrributeTest\nFormals: callback:_fn_(*)\nLocals: \nAnnotation: <> NonnullAtrributeTest(<_Nonnull>) \n DECLARE_LOCALS(&return); [line 46]\n " color=yellow style=filled] - "NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_1" -> "NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_4" ; + "NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_1" -> "NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_3" ; "NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_2" [label="2: Exit NonnullAtrributeTest \n " color=yellow style=filled] @@ -11,10 +11,6 @@ digraph iCFG { "NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_3" -> "NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_2" ; -"NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_4" [label="4: Call _fun___infer_assume \n n$1=*&callback:_fn_(*) [line 46]\n n$2=_fun___infer_assume((n$1 != 0):_fn_(*)) [line 46]\n " shape="box"] - - - "NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_4" -> "NonnullAtrributeTest.69a49728cf7d46ab0add381e5c93704c_3" ; "getA#NonnullA#instance.d4b29ece551a370c3f0c0c12526b3def_1" [label="1: Start NonnullA_getA\nFormals: self:class NonnullA*\nLocals: \n DECLARE_LOCALS(&return); [line 25]\n " color=yellow style=filled] @@ -26,10 +22,10 @@ digraph iCFG { "getA#NonnullA#instance.d4b29ece551a370c3f0c0c12526b3def_3" -> "getA#NonnullA#instance.d4b29ece551a370c3f0c0c12526b3def_2" ; -"initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_1" [label="1: Start NonnullC_initWithCoder:and:\nFormals: self:class NonnullC* aDecoder:class NSString* a:class NonnullA*\nLocals: y:int a1:class NonnullA* \n DECLARE_LOCALS(&return,&y,&a1); [line 38]\n " color=yellow style=filled] +"initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_1" [label="1: Start NonnullC_initWithCoder:and:\nFormals: self:class NonnullC* aDecoder:class NSString* a:class NonnullA*\nLocals: y:int a1:class NonnullA*\nAnnotation: <> NonnullC_initWithCoder:and:(<> <> <_Nonnull>) \n DECLARE_LOCALS(&return,&y,&a1); [line 38]\n " color=yellow style=filled] - "initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_1" -> "initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_6" ; + "initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_1" -> "initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_5" ; "initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_2" [label="2: Exit NonnullC_initWithCoder:and: \n " color=yellow style=filled] @@ -45,8 +41,4 @@ digraph iCFG { "initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_5" -> "initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_4" ; -"initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_6" [label="6: Call _fun___infer_assume \n n$5=*&a:class NonnullA* [line 38]\n n$6=_fun___infer_assume((n$5 != 0):class NonnullA*) [line 38]\n " shape="box"] - - - "initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_6" -> "initWithCoder:and:#NonnullC#instance.0360cbf0c434f47ea58689c925d7c008_5" ; }