Separate the flow of the frontend checks form the translation

Reviewed By: akotulski

Differential Revision: D3543519

fbshipit-source-id: 3493bbe
master
Dulma Churchill 9 years ago committed by Facebook Github Bot
parent 5566ca1fd9
commit 0253608fab

@ -421,19 +421,25 @@ let java_is_vararg =
}
| _ => false;
let is_obj_constructor method_name => method_name == "new" || string_is_prefix "init" method_name;
/** [is_constructor pname] returns true if [pname] is a constructor */
/** [is_constructor pname] returns true if [pname] is a constructor
TODO: add case for C++ */
let is_constructor =
fun
| Java js => js.method_name == "<init>"
| ObjC_Cpp name => name.method_name == "new" || string_is_prefix "init" name.method_name
| ObjC_Cpp name => is_obj_constructor name.method_name
| _ => false;
let is_objc_dealloc method_name => method_name == "dealloc";
/** [is_objc_dealloc pname] returns true if [pname] is the dealloc method in Objective-C */
let is_objc_dealloc =
/** [is_dealloc pname] returns true if [pname] is the dealloc method in Objective-C
TODO: add case for C++ */
let is_destructor =
fun
| ObjC_Cpp name => name.method_name == "dealloc"
| ObjC_Cpp name => is_objc_dealloc name.method_name
| _ => false;
let java_is_close =

@ -97,6 +97,10 @@ let is_anonymous_inner_class_name: string => bool;
let is_c_method: t => bool;
/** Check if this is a constructor method in Objective-C. */
let is_obj_constructor: string => bool;
/** Check if this is a constructor. */
let is_constructor: t => bool;
@ -106,7 +110,11 @@ let is_java: t => bool;
/** Check if this is a dealloc method in Objective-C. */
let is_objc_dealloc: t => bool;
let is_objc_dealloc: string => bool;
/** Check if this is a dealloc method. */
let is_destructor: t => bool;
/** Create a Java procedure name from its

@ -159,16 +159,3 @@ let rec get_outer_procname context =
| Some outer_context -> get_outer_procname outer_context
| None -> Cfg.Procdesc.get_proc_name context.procdesc
let is_curr_proc_objc_getter context field_name =
let attrs = Cfg.Procdesc.get_attributes context.procdesc in
match attrs.ProcAttributes.objc_accessor with
| Some ProcAttributes.Objc_getter field ->
(Ident.fieldname_to_string field) = field_name
| _ -> false
let is_curr_proc_objc_setter context field_name =
let attrs = Cfg.Procdesc.get_attributes context.procdesc in
match attrs.ProcAttributes.objc_accessor with
| Some ProcAttributes.Objc_setter field ->
(Ident.fieldname_to_string field) = field_name
| _ -> false

@ -70,7 +70,3 @@ val static_vars_for_block : t -> Procname.t -> (Pvar.t * Typ.t) list
val is_objc_instance : t -> bool
val get_outer_procname : t -> Procname.t
val is_curr_proc_objc_getter : t -> string -> bool
val is_curr_proc_objc_setter : t -> string -> bool

@ -60,6 +60,7 @@ let do_source_file source_file ast =
let call_graph, cfg = compute_icfg tenv ast in
Printing.log_out "\n End building call/cfg graph for '%s'.\n"
(DB.source_file_to_string source_file);
CFrontend_checkers_main.do_frontend_checks cfg call_graph ast;
(* This part below is a boilerplate in every frontends. *)
(* This could be moved in the cfg_infer module *)
let source_dir = DB.source_dir_from_source_file !DB.current_source in

@ -41,6 +41,20 @@ let get_ivar_attributes ivar_decl =
| _ -> [])
| _ -> []
let is_method_property_accessor_of_ivar method_decl ivar_pointer =
let open Clang_ast_t in
match method_decl with
| ObjCMethodDecl (_, _, obj_c_method_decl_info) ->
if obj_c_method_decl_info.Clang_ast_t.omdi_is_property_accessor then
let prperty_opt = obj_c_method_decl_info.Clang_ast_t.omdi_property_decl in
match Ast_utils.get_decl_opt_with_decl_ref prperty_opt with
| Some ObjCPropertyDecl (_, _, obj_c_property_decl_info) ->
(match obj_c_property_decl_info.Clang_ast_t.opdi_ivar_decl with
| Some decl_ref -> decl_ref.Clang_ast_t.dr_decl_pointer = ivar_pointer
| None -> false)
| _ -> false
else false
| _ -> false
(* checks if ivar is defined among a set of fields and if it is atomic *)
let is_ivar_atomic attributes =
@ -58,9 +72,6 @@ let location_from_sinfo info =
let location_from_dinfo info =
CLocation.get_sil_location_from_range info.Clang_ast_t.di_source_range true
let proc_name_from_context context =
Cfg.Procdesc.get_proc_name (CContext.get_procdesc context)
let rec is_self s =
let open Clang_ast_t in
match s with
@ -210,11 +221,14 @@ let global_var_init_with_calls_warning decl =
(* Direct Atomic Property access:
a property declared atomic should not be accessed directly via its ivar *)
let direct_atomic_property_access_warning context stmt_info ivar_decl_ref =
match Ast_utils.get_decl ivar_decl_ref.Clang_ast_t.dr_decl_pointer with
let direct_atomic_property_access_warning method_decl stmt_info ivar_decl_ref =
let ivar_pointer = ivar_decl_ref.Clang_ast_t.dr_decl_pointer in
match Ast_utils.get_decl ivar_pointer with
| Some (ObjCIvarDecl (_, named_decl_info, _, _, _) as d) ->
let method_name = match Clang_ast_proj.get_named_decl_tuple method_decl with
| Some (_, method_named_decl) -> method_named_decl.Clang_ast_t.ni_name
| _ -> "" in
let ivar_name = named_decl_info.Clang_ast_t.ni_name in
let mname = proc_name_from_context context in
let condition =
(* We give the warning when:
(1) the property has the atomic attribute and
@ -222,10 +236,9 @@ let direct_atomic_property_access_warning context stmt_info ivar_decl_ref =
(3) the access of the ivar is not in the init method
Last two conditions avoids false positives *)
is_ivar_atomic (get_ivar_attributes d)
&& not (CContext.is_curr_proc_objc_getter context ivar_name)
&& not (CContext.is_curr_proc_objc_setter context ivar_name)
&& not (Procname.is_constructor mname)
&& not (Procname.is_objc_dealloc mname) in
&& not (is_method_property_accessor_of_ivar method_decl ivar_pointer)
&& not (Procname.is_obj_constructor method_name)
&& not (Procname.is_objc_dealloc method_name) in
if condition then
Some {
name = "DIRECT_ATOMIC_PROPERTY_ACCESS";

@ -28,8 +28,8 @@ val assign_pointer_warning : Clang_ast_t.decl_info -> Clang_ast_t.named_decl_inf
(* Direct Atomic Property access:
a property declared atomic should not be accesses directly via its iva *)
val direct_atomic_property_access_warning :
CContext.t -> Clang_ast_t.stmt_info -> Clang_ast_t.decl_ref -> warning_desc option
val direct_atomic_property_access_warning : Clang_ast_t.decl -> Clang_ast_t.stmt_info ->
Clang_ast_t.decl_ref -> warning_desc option
(* CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK: C++ references
should not be captured in blocks. *)

@ -0,0 +1,42 @@
(*
* Copyright (c) 2016 - 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.
*)
let rec do_frontend_checks_stmt cfg cg method_decl stmt =
CFrontend_errors.run_frontend_checkers_on_stmt cfg cg method_decl stmt;
let _, stmts = Clang_ast_proj.get_stmt_tuple stmt in
IList.iter (do_frontend_checks_stmt cfg cg method_decl) stmts
let rec do_frontend_checks_decl cfg cg decl =
let open Clang_ast_t in
let info = Clang_ast_proj.get_decl_tuple decl in
CLocation.update_curr_file info;
(match decl with
| FunctionDecl(_, _, _, fdi)
| CXXMethodDecl (_, _, _, fdi, _)
| CXXConstructorDecl (_, _, _, fdi, _)
| CXXConversionDecl (_, _, _, fdi, _)
| CXXDestructorDecl (_, _, _, fdi, _) ->
(match fdi.Clang_ast_t.fdi_body with
| Some stmt -> do_frontend_checks_stmt cfg cg decl stmt
| None -> ())
| ObjCMethodDecl (_, _, mdi) ->
(match mdi.Clang_ast_t.omdi_body with
| Some stmt -> do_frontend_checks_stmt cfg cg decl stmt
| None -> ())
| _ -> ());
CFrontend_errors.run_frontend_checkers_on_decl cfg cg decl;
match Clang_ast_proj.get_decl_context_tuple decl with
| Some (decls, _) -> IList.iter (do_frontend_checks_decl cfg cg) decls
| None -> ()
let do_frontend_checks cfg cg ast =
match ast with
| Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) ->
IList.iter (do_frontend_checks_decl cfg cg) decl_list
| _ -> assert false (* NOTE: Assumes that an AST alsways starts with a TranslationUnitDecl *)

@ -0,0 +1,10 @@
(*
* Copyright (c) 2016 - 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.
*)
val do_frontend_checks : Cfg.cfg -> Cg.t -> Clang_ast_t.decl -> unit

@ -166,9 +166,6 @@ struct
(* Translate one global declaration *)
let rec translate_one_declaration tenv cg cfg decl_trans_context dec =
let open Clang_ast_t in
(* Run the frontend checkers on this declaration *)
if decl_trans_context = `DeclTraversal then
CFrontend_errors.run_frontend_checkers_on_decl cfg cg dec;
(* each procedure has different scope: start names from id 0 *)
Ident.NameGenerator.reset ();

@ -23,8 +23,8 @@ let checkers_for_property decl_info pname_info pdi checker =
let ivar_access_checker_list = [CFrontend_checkers.direct_atomic_property_access_warning]
(* Invocation of checker belonging to ivar_access_checker_list *)
let checkers_for_ivar context stmt_info dr_name checker =
checker context stmt_info dr_name
let checkers_for_ivar stmt_info method_decl ivar_decl_ref checker =
checker stmt_info method_decl ivar_decl_ref
(* List of checkers for captured vars in objc blocks *)
let captured_vars_checker_list = [CFrontend_checkers.captured_cxx_ref_in_objc_block_warning]
@ -48,9 +48,10 @@ let checker_for_global_var dec checker =
checker dec
(* Add a frontend warning with a description desc at location loc to the errlog of a proc desc *)
let log_frontend_warning pdesc warn_desc =
let log_frontend_warning cfg cg warn_desc =
let open CFrontend_checkers in
let loc = warn_desc.loc in
let pdesc = CMethod_trans.get_method_for_frontend_checks cfg cg loc in
let errlog = Cfg.Procdesc.get_err_log pdesc in
let err_desc =
Errdesc.explain_frontend_warning warn_desc.description warn_desc.suggestion loc in
@ -68,17 +69,10 @@ let log_frontend_warning pdesc warn_desc =
1. f a particular way to apply a checker, it's a partial function
2. context
3. the list of checkers to be applied *)
let invoke_set_of_checkers f cfg cg pdesc_opt checkers =
let invoke_set_of_checkers f cfg cg checkers =
IList.iter (fun checker ->
match f checker with
| Some warning_desc ->
let pdesc =
match pdesc_opt with
| Some pdesc -> pdesc
| None ->
let loc = warning_desc.CFrontend_checkers.loc in
CMethod_trans.get_method_for_frontend_checks cfg cg loc in
log_frontend_warning pdesc warning_desc
| Some warning_desc -> log_frontend_warning cfg cg warning_desc
| None -> ()) checkers
(* Call all checkers on properties of class c *)
@ -86,7 +80,7 @@ let rec check_for_property_errors cfg cg decl_list =
let open Clang_ast_t in
let do_one_property decl_info pname_info pdi =
let call_property_checker = checkers_for_property decl_info pname_info pdi in
invoke_set_of_checkers call_property_checker cfg cg None property_checkers_list in
invoke_set_of_checkers call_property_checker cfg cg property_checkers_list in
match decl_list with
| [] -> ()
| ObjCPropertyDecl (decl_info, pname_info, pdi) :: rest ->
@ -101,22 +95,17 @@ let get_categories_decls decl_ref =
| Some ObjCInterfaceDecl (_, _, decls, _, _) -> decls
| _ -> []
let run_frontend_checkers_on_stmt trans_state instr =
let run_frontend_checkers_on_stmt cfg cg method_decl instr =
let open Clang_ast_t in
let context = trans_state.CTrans_utils.context in
let pdesc = CContext.get_procdesc context in
let cg = context.CContext.cg in
let cfg = context.CContext.cfg in
match instr with
| ObjCIvarRefExpr(stmt_info, _, _, obj_c_ivar_ref_expr_info) ->
let dr_ref = obj_c_ivar_ref_expr_info.Clang_ast_t.ovrei_decl_ref in
let call_checker_for_ivar = checkers_for_ivar context stmt_info dr_ref in
invoke_set_of_checkers call_checker_for_ivar cfg cg (Some pdesc) ivar_access_checker_list
let call_checker_for_ivar = checkers_for_ivar method_decl stmt_info dr_ref in
invoke_set_of_checkers call_checker_for_ivar cfg cg ivar_access_checker_list
| BlockExpr(stmt_info, _ , _, Clang_ast_t.BlockDecl (_, block_decl_info)) ->
let captured_block_vars = block_decl_info.Clang_ast_t.bdi_captured_variables in
let call_captured_vars_checker = checkers_for_capture_vars stmt_info captured_block_vars in
let pdesc_opt = Some pdesc in
invoke_set_of_checkers call_captured_vars_checker cfg cg pdesc_opt captured_vars_checker_list
let call_captured_vars_checker = checkers_for_capture_vars stmt_info captured_block_vars in
invoke_set_of_checkers call_captured_vars_checker cfg cg captured_vars_checker_list
| _ -> ()
let rec run_frontend_checkers_on_decl cfg cg dec =
@ -132,14 +121,14 @@ let rec run_frontend_checkers_on_decl cfg cg dec =
let decls = (get_categories_decls idi.Clang_ast_t.oidi_class_interface) @ decl_list in
check_for_property_errors cfg cg decls;
let call_ns_checker = checkers_for_ns decl_info decl_list in
invoke_set_of_checkers call_ns_checker cfg cg None ns_notification_checker_list;
invoke_set_of_checkers call_ns_checker cfg cg ns_notification_checker_list;
IList.iter (run_frontend_checkers_on_decl cfg cg) decl_list
| ObjCProtocolDecl (decl_info, _, decl_list, _, _) ->
check_for_property_errors cfg cg decl_list;
let call_ns_checker = checkers_for_ns decl_info decl_list in
invoke_set_of_checkers call_ns_checker cfg cg None ns_notification_checker_list;
invoke_set_of_checkers call_ns_checker cfg cg ns_notification_checker_list;
IList.iter (run_frontend_checkers_on_decl cfg cg) decl_list
| VarDecl _ ->
let call_global_checker = checker_for_global_var dec in
invoke_set_of_checkers call_global_checker cfg cg None global_var_checker_list
invoke_set_of_checkers call_global_checker cfg cg global_var_checker_list
| _ -> ()

@ -13,7 +13,7 @@ open! Utils
(* Module for warnings detected at translation time by the frontend *)
(* Run frontend checkers on a statement *)
val run_frontend_checkers_on_stmt : CTrans_utils.trans_state -> Clang_ast_t.stmt -> unit
val run_frontend_checkers_on_stmt : Cfg.cfg -> Cg.t -> Clang_ast_t.decl -> Clang_ast_t.stmt -> unit
(* Run frontend checkers on a declaration *)
val run_frontend_checkers_on_decl : Cfg.cfg -> Cg.t -> Clang_ast_t.decl -> unit

@ -2314,8 +2314,6 @@ struct
(* a trans_state containing current info on the translation and it returns *)
(* a result_state.*)
and instruction trans_state instr =
(* Run the frontend checkers on this instruction *)
CFrontend_errors.run_frontend_checkers_on_stmt trans_state instr;
let stmt_kind = Clang_ast_proj.get_stmt_kind_string instr in
let stmt_info, _ = Clang_ast_proj.get_stmt_tuple instr in
let stmt_pointer = stmt_info.Clang_ast_t.si_pointer in

@ -1,145 +1,145 @@
/* @generated */
digraph iCFG {
37 [label="37: DeclStmt \n n$4=_fun___objc_alloc_no_fail(sizeof(class NSAutoreleasePool ):unsigned long ) [line 60]\n n$5=_fun_NSObject_init(n$4:class NSAutoreleasePool *) virtual [line 60]\n *&pool:class NSAutoreleasePool *=n$5 [line 60]\n " shape="box"]
37 [label="37: Exit frontend_checks_260aba1187e75a8c3340e4b361681569 \n " color=yellow style=filled]
37 -> 36 ;
36 [label="36: DeclStmt \n n$2=_fun___objc_alloc_no_fail(sizeof(class NSString ):unsigned long ) [line 61]\n n$3=_fun___set_autorelease_attribute(n$2:class NSString *) [line 61]\n *&string:class NSString *=n$3 [line 61]\n " shape="box"]
36 [label="36: Start frontend_checks_260aba1187e75a8c3340e4b361681569\nFormals: \nLocals: \n " color=yellow style=filled]
36 -> 35 ;
35 [label="35: Message Call: release \n n$1=*&pool:class NSAutoreleasePool * [line 63]\n _fun___objc_release_autorelease_pool(n$1:class NSAutoreleasePool *) [line 63]\n " shape="box"]
36 -> 37 ;
35 [label="35: DeclStmt \n n$4=_fun___objc_alloc_no_fail(sizeof(class NSAutoreleasePool ):unsigned long ) [line 60]\n n$5=_fun_NSObject_init(n$4:class NSAutoreleasePool *) virtual [line 60]\n *&pool:class NSAutoreleasePool *=n$5 [line 60]\n " shape="box"]
35 -> 34 ;
34 [label="34: DeclStmt \n n$0=*&string:class NSString * [line 64]\n *&c:class NSString *=n$0 [line 64]\n " shape="box"]
34 [label="34: DeclStmt \n n$2=_fun___objc_alloc_no_fail(sizeof(class NSString ):unsigned long ) [line 61]\n n$3=_fun___set_autorelease_attribute(n$2:class NSString *) [line 61]\n *&string:class NSString *=n$3 [line 61]\n " shape="box"]
34 -> 33 ;
33 [label="33: Exit test3 \n " color=yellow style=filled]
33 [label="33: Message Call: release \n n$1=*&pool:class NSAutoreleasePool * [line 63]\n _fun___objc_release_autorelease_pool(n$1:class NSAutoreleasePool *) [line 63]\n " shape="box"]
32 [label="32: Start test3\nFormals: \nLocals: c:class NSString * string:class NSString * pool:class NSAutoreleasePool * \n DECLARE_LOCALS(&return,&c,&string,&pool); [line 59]\n " color=yellow style=filled]
33 -> 32 ;
32 [label="32: DeclStmt \n n$0=*&string:class NSString * [line 64]\n *&c:class NSString *=n$0 [line 64]\n " shape="box"]
32 -> 37 ;
31 [label="31: DeclStmt \n *&s1:class A *=0 [line 48]\n " shape="box"]
32 -> 31 ;
31 [label="31: Exit test3 \n " color=yellow style=filled]
31 -> 30 ;
30 [label="30: DeclStmt \n *&s2:class A *=0 [line 49]\n " shape="box"]
30 [label="30: Start test3\nFormals: \nLocals: c:class NSString * string:class NSString * pool:class NSAutoreleasePool * \n DECLARE_LOCALS(&return,&c,&string,&pool); [line 59]\n " color=yellow style=filled]
30 -> 29 ;
29 [label="29: DeclStmt \n *&s3:class A *=0 [line 50]\n " shape="box"]
30 -> 35 ;
29 [label="29: DeclStmt \n *&s1:class A *=0 [line 48]\n " shape="box"]
29 -> 28 ;
28 [label="28: BinaryOperatorStmt: Assign \n n$3=_fun_createA() [line 52]\n *&s1:class A *=n$3 [line 52]\n " shape="box"]
28 [label="28: DeclStmt \n *&s2:class A *=0 [line 49]\n " shape="box"]
28 -> 27 ;
27 [label="27: BinaryOperatorStmt: Assign \n n$2=_fun_createA() [line 53]\n *&s2:class A *=n$2 [line 53]\n " shape="box"]
27 [label="27: DeclStmt \n *&s3:class A *=0 [line 50]\n " shape="box"]
27 -> 26 ;
26 [label="26: BinaryOperatorStmt: Assign \n n$1=_fun_createA() [line 54]\n *&s3:class A *=n$1 [line 54]\n " shape="box"]
26 [label="26: BinaryOperatorStmt: Assign \n n$3=_fun_createA() [line 52]\n *&s1:class A *=n$3 [line 52]\n " shape="box"]
26 -> 25 ;
25 [label="25: Release the autorelease pool \n n$0=_fun___objc_release_autorelease_pool(&s1:class A *,&s3:class A *,&s2:class A *) [line 51]\n " shape="box"]
25 [label="25: BinaryOperatorStmt: Assign \n n$2=_fun_createA() [line 53]\n *&s2:class A *=n$2 [line 53]\n " shape="box"]
25 -> 24 ;
24 [label="24: Return Stmt \n *&return:int =0 [line 56]\n " shape="box"]
24 [label="24: BinaryOperatorStmt: Assign \n n$1=_fun_createA() [line 54]\n *&s3:class A *=n$1 [line 54]\n " shape="box"]
24 -> 23 ;
23 [label="23: Exit test2 \n " color=yellow style=filled]
23 [label="23: Release the autorelease pool \n n$0=_fun___objc_release_autorelease_pool(&s1:class A *,&s3:class A *,&s2:class A *) [line 51]\n " shape="box"]
22 [label="22: Start test2\nFormals: \nLocals: s3:class A * s2:class A * s1:class A * \n DECLARE_LOCALS(&return,&s3,&s2,&s1); [line 47]\n " color=yellow style=filled]
23 -> 22 ;
22 [label="22: Return Stmt \n *&return:int =0 [line 56]\n " shape="box"]
22 -> 31 ;
21 [label="21: DeclStmt \n *&s1:class A *=0 [line 35]\n " shape="box"]
22 -> 21 ;
21 [label="21: Exit test2 \n " color=yellow style=filled]
21 -> 20 ;
20 [label="20: DeclStmt \n *&s2:class A *=0 [line 36]\n " shape="box"]
20 [label="20: Start test2\nFormals: \nLocals: s3:class A * s2:class A * s1:class A * \n DECLARE_LOCALS(&return,&s3,&s2,&s1); [line 47]\n " color=yellow style=filled]
20 -> 19 ;
19 [label="19: DeclStmt \n *&s3:class A *=0 [line 37]\n " shape="box"]
20 -> 29 ;
19 [label="19: DeclStmt \n *&s1:class A *=0 [line 35]\n " shape="box"]
19 -> 18 ;
18 [label="18: BinaryOperatorStmt: Assign \n n$5=_fun_createA() [line 39]\n *&s1:class A *=n$5 [line 39]\n " shape="box"]
18 [label="18: DeclStmt \n *&s2:class A *=0 [line 36]\n " shape="box"]
18 -> 17 ;
17 [label="17: Message Call: retain \n n$3=*&s1:class A * [line 40]\n n$4=_fun___objc_retain(n$3:class A *) [line 40]\n " shape="box"]
17 [label="17: DeclStmt \n *&s3:class A *=0 [line 37]\n " shape="box"]
17 -> 16 ;
16 [label="16: BinaryOperatorStmt: Assign \n n$2=_fun_createA() [line 41]\n *&s2:class A *=n$2 [line 41]\n " shape="box"]
16 [label="16: BinaryOperatorStmt: Assign \n n$5=_fun_createA() [line 39]\n *&s1:class A *=n$5 [line 39]\n " shape="box"]
16 -> 15 ;
15 [label="15: BinaryOperatorStmt: Assign \n n$1=_fun_createA() [line 42]\n *&s3:class A *=n$1 [line 42]\n " shape="box"]
15 [label="15: Message Call: retain \n n$3=*&s1:class A * [line 40]\n n$4=_fun___objc_retain(n$3:class A *) [line 40]\n " shape="box"]
15 -> 14 ;
14 [label="14: Release the autorelease pool \n n$0=_fun___objc_release_autorelease_pool(&s1:class A *,&s2:class A *,&s3:class A *) [line 38]\n " shape="box"]
14 [label="14: BinaryOperatorStmt: Assign \n n$2=_fun_createA() [line 41]\n *&s2:class A *=n$2 [line 41]\n " shape="box"]
14 -> 13 ;
13 [label="13: Return Stmt \n *&return:int =0 [line 44]\n " shape="box"]
13 [label="13: BinaryOperatorStmt: Assign \n n$1=_fun_createA() [line 42]\n *&s3:class A *=n$1 [line 42]\n " shape="box"]
13 -> 12 ;
12 [label="12: Exit test1 \n " color=yellow style=filled]
12 [label="12: Release the autorelease pool \n n$0=_fun___objc_release_autorelease_pool(&s1:class A *,&s2:class A *,&s3:class A *) [line 38]\n " shape="box"]
11 [label="11: Start test1\nFormals: \nLocals: s3:class A * s2:class A * s1:class A * \n DECLARE_LOCALS(&return,&s3,&s2,&s1); [line 34]\n " color=yellow style=filled]
12 -> 11 ;
11 [label="11: Return Stmt \n *&return:int =0 [line 44]\n " shape="box"]
11 -> 21 ;
10 [label="10: DeclStmt \n n$2=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 30]\n n$3=_fun_NSObject_init(n$2:class A *) virtual [line 30]\n *&s1:class A *=n$3 [line 30]\n " shape="box"]
11 -> 10 ;
10 [label="10: Exit test1 \n " color=yellow style=filled]
10 -> 9 ;
9 [label="9: Return Stmt \n n$0=*&s1:class A * [line 31]\n n$1=_fun___set_autorelease_attribute(n$0:class A *) [line 31]\n *&return:class A *=n$1 [line 31]\n " shape="box"]
9 [label="9: Start test1\nFormals: \nLocals: s3:class A * s2:class A * s1:class A * \n DECLARE_LOCALS(&return,&s3,&s2,&s1); [line 34]\n " color=yellow style=filled]
9 -> 8 ;
8 [label="8: Exit createA \n " color=yellow style=filled]
9 -> 19 ;
8 [label="8: DeclStmt \n n$2=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 30]\n n$3=_fun_NSObject_init(n$2:class A *) virtual [line 30]\n *&s1:class A *=n$3 [line 30]\n " shape="box"]
7 [label="7: Start createA\nFormals: \nLocals: s1:class A * \n DECLARE_LOCALS(&return,&s1); [line 29]\n " color=yellow style=filled]
8 -> 7 ;
7 [label="7: Return Stmt \n n$0=*&s1:class A * [line 31]\n n$1=_fun___set_autorelease_attribute(n$0:class A *) [line 31]\n *&return:class A *=n$1 [line 31]\n " shape="box"]
7 -> 10 ;
6 [label="6: DeclStmt \n n$2=_fun___objc_alloc_no_fail(sizeof(class NSString ):unsigned long ) [line 23]\n *&s:class NSString *=n$2 [line 23]\n " shape="box"]
7 -> 6 ;
6 [label="6: Exit createA \n " color=yellow style=filled]
6 -> 5 ;
5 [label="5: Return Stmt \n n$0=*&s:class NSString * [line 24]\n n$1=_fun___set_autorelease_attribute(n$0:class NSString *) [line 24]\n *&return:class NSString *=n$1 [line 24]\n " shape="box"]
5 [label="5: Start createA\nFormals: \nLocals: s1:class A * \n DECLARE_LOCALS(&return,&s1); [line 29]\n " color=yellow style=filled]
5 -> 4 ;
4 [label="4: Exit A_main \n " color=yellow style=filled]
5 -> 8 ;
4 [label="4: DeclStmt \n n$2=_fun___objc_alloc_no_fail(sizeof(class NSString ):unsigned long ) [line 23]\n *&s:class NSString *=n$2 [line 23]\n " shape="box"]
3 [label="3: Start A_main\nFormals: self:class A *\nLocals: s:class NSString * \n DECLARE_LOCALS(&return,&s); [line 22]\n " color=yellow style=filled]
4 -> 3 ;
3 [label="3: Return Stmt \n n$0=*&s:class NSString * [line 24]\n n$1=_fun___set_autorelease_attribute(n$0:class NSString *) [line 24]\n *&return:class NSString *=n$1 [line 24]\n " shape="box"]
3 -> 6 ;
2 [label="2: Exit frontend_checks_260aba1187e75a8c3340e4b361681569 \n " color=yellow style=filled]
3 -> 2 ;
2 [label="2: Exit A_main \n " color=yellow style=filled]
1 [label="1: Start frontend_checks_260aba1187e75a8c3340e4b361681569\nFormals: \nLocals: \n " color=yellow style=filled]
1 [label="1: Start A_main\nFormals: self:class A *\nLocals: s:class NSString * \n DECLARE_LOCALS(&return,&s); [line 22]\n " color=yellow style=filled]
1 -> 2 ;
1 -> 4 ;
}

@ -1,73 +1,73 @@
/* @generated */
digraph iCFG {
18 [label="18: DeclStmt \n n$3=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 39]\n n$4=_fun_NSObject_init(n$3:class A *) virtual [line 39]\n *&a:class A *=n$4 [line 39]\n " shape="box"]
18 [label="18: Exit frontend_checks_23a4fcc8f25cc8087aa9202ac0edfbf5 \n " color=yellow style=filled]
18 -> 17 ;
17 [label="17: Message Call: setLast_name: \n n$1=*&a:class A * [line 40]\n n$2=*&a2:class A * [line 40]\n _fun_A_setLast_name:(n$1:class A *,n$2:class A *) [line 40]\n " shape="box"]
17 [label="17: Start frontend_checks_23a4fcc8f25cc8087aa9202ac0edfbf5\nFormals: \nLocals: \n " color=yellow style=filled]
17 -> 16 ;
16 [label="16: Message Call: release \n n$0=*&a:class A * [line 41]\n _fun___objc_release(n$0:class A *) [line 41]\n " shape="box"]
17 -> 18 ;
16 [label="16: DeclStmt \n n$3=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 39]\n n$4=_fun_NSObject_init(n$3:class A *) virtual [line 39]\n *&a:class A *=n$4 [line 39]\n " shape="box"]
16 -> 15 ;
15 [label="15: Return Stmt \n *&return:int =0 [line 42]\n " shape="box"]
15 [label="15: Message Call: setLast_name: \n n$1=*&a:class A * [line 40]\n n$2=*&a2:class A * [line 40]\n _fun_A_setLast_name:(n$1:class A *,n$2:class A *) [line 40]\n " shape="box"]
15 -> 14 ;
14 [label="14: Exit test \n " color=yellow style=filled]
14 [label="14: Message Call: release \n n$0=*&a:class A * [line 41]\n _fun___objc_release(n$0:class A *) [line 41]\n " shape="box"]
13 [label="13: Start test\nFormals: a2:class A *\nLocals: a:class A * \n DECLARE_LOCALS(&return,&a); [line 38]\n " color=yellow style=filled]
14 -> 13 ;
13 [label="13: Return Stmt \n *&return:int =0 [line 42]\n " shape="box"]
13 -> 18 ;
12 [label="12: DeclStmt \n n$11=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 27]\n n$12=_fun_NSObject_init(n$11:class A *) virtual [line 27]\n *&other:class A *=n$12 [line 27]\n " shape="box"]
13 -> 12 ;
12 [label="12: Exit test \n " color=yellow style=filled]
12 -> 7 ;
12 -> 8 ;
11 [label="11: BinaryOperatorStmt: Assign \n n$8=*&other:class A * [line 29]\n n$9=*&self:class A * [line 29]\n n$10=*n$9._name:class A * [line 29]\n *n$8._name:class A *=n$10 [line 29]\n " shape="box"]
11 [label="11: Start test\nFormals: a2:class A *\nLocals: a:class A * \n DECLARE_LOCALS(&return,&a); [line 38]\n " color=yellow style=filled]
11 -> 10 ;
10 [label="10: BinaryOperatorStmt: Assign \n n$5=*&other:class A * [line 30]\n n$6=*&self:class A * [line 30]\n n$7=*n$6._last_name:class A * [line 30]\n *n$5._last_name:class A *=n$7 [line 30]\n " shape="box"]
11 -> 16 ;
10 [label="10: DeclStmt \n n$11=_fun___objc_alloc_no_fail(sizeof(class A ):unsigned long ) [line 27]\n n$12=_fun_NSObject_init(n$11:class A *) virtual [line 27]\n *&other:class A *=n$12 [line 27]\n " shape="box"]
10 -> 9 ;
9 [label="9: BinaryOperatorStmt: Assign \n n$2=*&other:class A * [line 31]\n n$3=*&self:class A * [line 31]\n n$4=*n$3._child:class A * [line 31]\n *n$2._child:class A *=n$4 [line 31]\n " shape="box"]
10 -> 5 ;
10 -> 6 ;
9 [label="9: BinaryOperatorStmt: Assign \n n$8=*&other:class A * [line 29]\n n$9=*&self:class A * [line 29]\n n$10=*n$9._name:class A * [line 29]\n *n$8._name:class A *=n$10 [line 29]\n " shape="box"]
9 -> 6 ;
8 [label="8: Prune (false branch) \n n$1=*&other:class A * [line 28]\n PRUNE((n$1 == 0), false); [line 28]\n " shape="invhouse"]
9 -> 8 ;
8 [label="8: BinaryOperatorStmt: Assign \n n$5=*&other:class A * [line 30]\n n$6=*&self:class A * [line 30]\n n$7=*n$6._last_name:class A * [line 30]\n *n$5._last_name:class A *=n$7 [line 30]\n " shape="box"]
8 -> 6 ;
7 [label="7: Prune (true branch) \n n$1=*&other:class A * [line 28]\n PRUNE((n$1 != 0), true); [line 28]\n " shape="invhouse"]
8 -> 7 ;
7 [label="7: BinaryOperatorStmt: Assign \n n$2=*&other:class A * [line 31]\n n$3=*&self:class A * [line 31]\n n$4=*n$3._child:class A * [line 31]\n *n$2._child:class A *=n$4 [line 31]\n " shape="box"]
7 -> 11 ;
6 [label="6: + \n " ]
7 -> 4 ;
6 [label="6: Prune (false branch) \n n$1=*&other:class A * [line 28]\n PRUNE((n$1 == 0), false); [line 28]\n " shape="invhouse"]
6 -> 5 ;
5 [label="5: Return Stmt \n n$0=*&other:class A * [line 33]\n *&return:class A *=n$0 [line 33]\n " shape="box"]
6 -> 4 ;
5 [label="5: Prune (true branch) \n n$1=*&other:class A * [line 28]\n PRUNE((n$1 != 0), true); [line 28]\n " shape="invhouse"]
5 -> 4 ;
4 [label="4: Exit A_copy \n " color=yellow style=filled]
5 -> 9 ;
4 [label="4: + \n " ]
3 [label="3: Start A_copy\nFormals: self:class A *\nLocals: other:class A * \n DECLARE_LOCALS(&return,&other); [line 26]\n " color=yellow style=filled]
4 -> 3 ;
3 [label="3: Return Stmt \n n$0=*&other:class A * [line 33]\n *&return:class A *=n$0 [line 33]\n " shape="box"]
3 -> 12 ;
2 [label="2: Exit frontend_checks_23a4fcc8f25cc8087aa9202ac0edfbf5 \n " color=yellow style=filled]
3 -> 2 ;
2 [label="2: Exit A_copy \n " color=yellow style=filled]
1 [label="1: Start frontend_checks_23a4fcc8f25cc8087aa9202ac0edfbf5\nFormals: \nLocals: \n " color=yellow style=filled]
1 [label="1: Start A_copy\nFormals: self:class A *\nLocals: other:class A * \n DECLARE_LOCALS(&return,&other); [line 26]\n " color=yellow style=filled]
1 -> 2 ;
1 -> 10 ;
}

@ -74,6 +74,7 @@
}
- (int)readP {
int i = _q; // Bad access
return _p; // Good access
}

@ -11,6 +11,7 @@ package endtoend.objc;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsExactly.containsExactly;
import static utils.matchers.ResultContainsLineNumbers.containsLines;
import com.google.common.collect.ImmutableList;
@ -46,22 +47,19 @@ public class AtomicPropertyTest {
}
@Test
public void whenInferRunsOnAtomicProperty()
public void matchErrors()
throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferObjC(inferCmd);
assertThat(
"Results should contain a direct atomic property access",
"Results should contain the correct " + DIRECT_ATOMIC_PROPERTY_ACCESS,
inferResults,
containsExactly(
DIRECT_ATOMIC_PROPERTY_ACCESS,
FILE,
new String[]{
"writeQ:",
"readQ",
"bla"
}
)
);
containsLines(new int[]{
77,
82,
86,
98,
99
}));
}
}

@ -11,6 +11,7 @@ package endtoend.objc;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsExactly.containsExactly;
import static utils.matchers.ResultContainsLineNumbers.containsLines;
import com.google.common.collect.ImmutableList;
@ -43,20 +44,15 @@ public class BlockCaptureCXXRefTest {
}
@Test
public void whenInferRunsOnNavigateToURLInBackgroundThenNPEIsFound()
public void matchErrors()
throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferObjC(inferCmd);
String[] procedures = {
"foo:", "foo3:param2:"
};
assertThat(
"Results should contain the expected C++ reference captured in block",
"Results should contain the correct " + REFERENCE_CAPTURED,
inferResults,
containsExactly(
REFERENCE_CAPTURED,
FILE,
procedures
)
);
containsLines(new int[]{
20,
37
}));
}
}

Loading…
Cancel
Save