[ios] Translate nonnull annotations and take them into account in parameter not null checked issues.

Reviewed By: sblackshear

Differential Revision: D4706345

fbshipit-source-id: c7e0065
master
Dulma Churchill 8 years ago committed by Facebook Github Bot
parent c695616eff
commit 565ce2166d

@ -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
(** 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 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
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
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 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 =
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) -> Annotations.ia_is_nullable annot
| Some (_, annot) -> is_annotation 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
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
List.for_all ~f:is_strexp_pt_by_nullable_fld flds
| _ -> true)
prop.Prop.sigma &&
!nullable_obj_str <> None 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 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 ""

@ -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

@ -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

@ -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

@ -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

@ -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 =

@ -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) =

@ -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

@ -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 \

@ -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]

@ -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

@ -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 <Foundation/NSObject.h>
@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

@ -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" ;
}

@ -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" ;
}

Loading…
Cancel
Save