diff --git a/infer/src/backend/procname.ml b/infer/src/backend/procname.ml index 55b375d9b..cb77462e5 100644 --- a/infer/src/backend/procname.ml +++ b/infer/src/backend/procname.ml @@ -1,12 +1,12 @@ (* - * Copyright (c) 2009 - 2013 Monoidics ltd. - * Copyright (c) 2013 - 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. - *) +* Copyright (c) 2009 - 2013 Monoidics ltd. +* Copyright (c) 2013 - 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. +*) (** Module for Procedure Names *) @@ -30,6 +30,19 @@ type java_signature = { kind: method_kind } +type objc_method_kind = + | Instance_objc_method + | Class_objc_method + +let mangled_of_objc_method_kind kind = + match kind with + | Instance_objc_method -> Some "instance" + | Class_objc_method -> Some "class" + +let objc_method_kind_of_bool is_instance = + if is_instance then Instance_objc_method + else Class_objc_method + (* C++/ObjC method signature *) type c_method_signature = { class_name: string; @@ -117,10 +130,19 @@ let java_sig_compare js1 js2 = |> next java_return_type_compare js1.returntype js2.returntype |> next method_kind_compare js1.kind js2.kind +let c_function_mangled_compare mangled1 mangled2 = + match mangled1, mangled2 with + | Some mangled1, None -> 1 + | None, Some mangled2 -> -1 + | None, None -> 0 + | Some mangled1, Some mangled2 -> + string_compare mangled1 mangled2 + (** Compare c_method signatures. *) let c_meth_sig_compare osig1 osig2 = - let n = string_compare osig1.class_name osig2.class_name in - if n <> 0 then n else string_compare osig1.method_name osig2.method_name + string_compare osig1.method_name osig2.method_name + |> next string_compare osig1.class_name osig2.class_name + |> next c_function_mangled_compare osig1.mangled osig2.mangled (** Given a package.classname string, it looks for the latest dot and split the string in two (package, classname) *) let split_classname package_classname = @@ -357,9 +379,9 @@ let to_readable_string (c1, c2) verbose = let c_method_to_string osig detail_level = match detail_level with - | SIMPLE -> - osig.method_name - | VERBOSE | NON_VERBOSE -> + | SIMPLE -> osig.method_name + | NON_VERBOSE -> osig.class_name ^ "_" ^ osig.method_name + | VERBOSE -> let m_str = match osig.mangled with | None -> "" | Some s -> "{" ^ s ^ "}" in diff --git a/infer/src/backend/procname.mli b/infer/src/backend/procname.mli index 1a292c348..5445919cb 100644 --- a/infer/src/backend/procname.mli +++ b/infer/src/backend/procname.mli @@ -21,6 +21,16 @@ type method_kind = | Static (* in Java, procedures called with invokestatic *) | Non_Static (* in Java, procedures called with invokevirtual, invokespecial, and invokeinterface *) +type objc_method_kind = + | Instance_objc_method (* for instance methods in ObjC *) + | Class_objc_method (* for class methods in ObjC *) + +(** Mangled string for method types *) +val mangled_of_objc_method_kind : objc_method_kind -> string option + +(** Create ObjC method type from a bool is_instance *) +val objc_method_kind_of_bool : bool -> objc_method_kind + (** Comparison for proc names *) val compare : t -> t -> int diff --git a/infer/src/backend/symExec.ml b/infer/src/backend/symExec.ml index 124ea6ae6..69f8c3e5e 100644 --- a/infer/src/backend/symExec.ml +++ b/infer/src/backend/symExec.ml @@ -1,12 +1,12 @@ (* - * Copyright (c) 2009 - 2013 Monoidics ltd. - * Copyright (c) 2013 - 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. - *) +* Copyright (c) 2009 - 2013 Monoidics ltd. +* Copyright (c) 2013 - 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. +*) (** Symbolic Execution *) @@ -511,13 +511,11 @@ let check_inherently_dangerous_function caller_pname callee_pname = let pre_opt = State.get_normalized_pre (Abs.abstract_no_symop caller_pname) in Reporting.log_warning caller_pname ~pre: pre_opt exn - let is_defined cfg pname = match Cfg.Procdesc.find_from_name cfg pname with | None -> false | Some pdesc -> Cfg.Procdesc.is_defined pdesc - let call_should_be_skipped callee_pname summary = (* skip all procedures in intra-precedural mode *) !Config.intraprocedural @@ -528,7 +526,6 @@ let call_should_be_skipped callee_pname summary = (* treat calls with no specs as skip functions in angelic mode *) || (!Config.angelic_execution && Specs.get_specs_from_payload summary == []) - let report_raise_memory_leak tenv msg hpred prop = L.d_strln msg; L.d_increase_indent 1; @@ -663,7 +660,6 @@ let method_exists right_proc_name methods = else (* ObjC case *) Specs.summary_exists right_proc_name - let resolve_method tenv class_name proc_name = let found_class = let visited = ref Mangled.MangledSet.empty in @@ -694,7 +690,6 @@ let resolve_method tenv class_name proc_name = proc_name | Some proc_name -> proc_name - let resolve_typename prop arg = let (arg_exp, _) = arg in let typexp_opt = @@ -707,7 +702,6 @@ let resolve_typename prop arg = | Some (Sil.Sizeof (Sil.Tstruct (_, _, Sil.Class, class_name_opt, _, _, _), _)) -> class_name_opt | _ -> None - (** If the dynamic type of the object calling a method is known, the method from the dynamic type is called *) let resolve_virtual_pname cfg tenv prop args pname : Procname.t = @@ -1226,7 +1220,7 @@ and call_unknown_or_scan is_scan cfg pdesc tenv pre path let path_pos = State.get_path_pos () in [(Prop.mark_vars_as_undefined pre''' exps_to_mark callee_pname loc path_pos, path)] -and sym_exe_check_variadic_sentinel ?(fails_on_nil=false) cfg pdesc tenv prop path n_formals actual_params (sentinel, null_pos) callee_pname loc = +and sym_exe_check_variadic_sentinel ?(fails_on_nil = false) cfg pdesc tenv prop path n_formals actual_params (sentinel, null_pos) callee_pname loc = (* from clang's lib/Sema/SemaExpr.cpp: *) (* "nullPos" is the number of formal parameters at the end which *) (* effectively count as part of the variadic arguments. This is *) @@ -1237,8 +1231,8 @@ and sym_exe_check_variadic_sentinel ?(fails_on_nil=false) cfg pdesc tenv prop pa (* sentinels start counting from the last argument to the function *) let sentinel_pos = nargs - sentinel - 1 in let mk_non_terminal_argsi (acc, i) a = - if i < first_var_arg_pos || i >= sentinel_pos then (acc, i+1) - else ((a,i)::acc, i+1) in + if i < first_var_arg_pos || i >= sentinel_pos then (acc, i +1) + else ((a, i):: acc, i +1) in (* list_fold_left reverses the arguments *) let non_terminal_argsi = fst (list_fold_left mk_non_terminal_argsi ([], 0) actual_params) in let check_allocated result ((lexp, typ), i) = @@ -1261,14 +1255,13 @@ and sym_exe_check_variadic_sentinel ?(fails_on_nil=false) cfg pdesc tenv prop pa (* error on the first premature nil argument *) list_fold_left check_allocated [(prop, path)] non_terminal_argsi - and sym_exe_check_variadic_sentinel_if_present cfg pdesc tenv prop path actual_params callee_pname loc = match Cfg.Procdesc.find_from_name cfg callee_pname with | None -> [(prop, path)] | Some callee_pdesc -> let proc_attributes = Cfg.Procdesc.get_attributes callee_pdesc in match Sil.get_sentinel_func_attribute_value proc_attributes.Sil.func_attributes with - | None -> [(prop,path)] + | None -> [(prop, path)] | Some sentinel_arg -> let formals = Cfg.Procdesc.get_formals callee_pdesc in sym_exe_check_variadic_sentinel cfg pdesc tenv prop path (list_length formals) actual_params sentinel_arg callee_pname loc @@ -2312,7 +2305,7 @@ module ModelBuiltins = struct let execute_NSArray_arrayWithObjects_count cfg pdesc instr tenv prop path ret_ids args callee_pname loc = let n_formals = 1 in - let res' = sym_exe_check_variadic_sentinel ~fails_on_nil:true cfg pdesc tenv prop path n_formals args (0,1) callee_pname loc in + let res' = sym_exe_check_variadic_sentinel ~fails_on_nil: true cfg pdesc tenv prop path n_formals args (0,1) callee_pname loc in execute_objc_NSArray_alloc_no_fail cfg pdesc tenv res' ret_ids loc let execute_NSArray_arrayWithObjects cfg pdesc instr tenv prop path ret_ids args callee_pname loc = @@ -2321,12 +2314,14 @@ module ModelBuiltins = struct execute_objc_NSArray_alloc_no_fail cfg pdesc tenv res' ret_ids loc let _ = + let method_kind = Procname.mangled_of_objc_method_kind Procname.Class_objc_method in Builtin.register_procname - (Procname.mangled_c_method "NSArray" "arrayWithObjects:count:" None) + (Procname.mangled_c_method "NSArray" "arrayWithObjects:count:" method_kind) execute_NSArray_arrayWithObjects_count let _ = + let method_kind = Procname.mangled_of_objc_method_kind Procname.Class_objc_method in Builtin.register_procname - (Procname.mangled_c_method "NSArray" "arrayWithObjects:" None) + (Procname.mangled_c_method "NSArray" "arrayWithObjects:" method_kind) execute_NSArray_arrayWithObjects end (* ============== END of ModelBuiltins ============== *) diff --git a/infer/src/clang/cMethod_decl.ml b/infer/src/clang/cMethod_decl.ml index ec68ef9fb..b3f4c82c8 100644 --- a/infer/src/clang/cMethod_decl.ml +++ b/infer/src/clang/cMethod_decl.ml @@ -171,7 +171,9 @@ struct let process_objc_method_decl tenv cg cfg namespace curr_class decl_info name_info method_decl_info = let class_name = CContext.get_curr_class_name curr_class in let method_name = name_info.Clang_ast_t.ni_name in - let procname = CMethod_trans.mk_procname_from_method class_name method_name in + let is_instance = method_decl_info.Clang_ast_t.omdi_is_instance_method in + let method_kind = Procname.objc_method_kind_of_bool is_instance in + let procname = CMethod_trans.mk_procname_from_method class_name method_name method_kind in let method_decl = Meth_decl_info (method_decl_info, class_name) in let is_generated = Ast_utils.is_generated name_info in let ms = build_method_signature decl_info procname method_decl false false is_generated in diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index f338136c2..db963908b 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -30,25 +30,9 @@ let mk_procname_from_function name type_name = let type_name_crc = CRC.crc16 type_name in Procname.mangled_c_fun name type_name_crc -let mk_procname_from_method class_name method_name = - Procname.mangled_c_method class_name method_name None - -let resolve_method_class tenv class_name method_name = - let type_name = Sil.TN_csu (Sil.Class, class_name) in - match Sil.tenv_lookup tenv type_name with - | Some (Sil.Tstruct (_, _, Sil.Class, cls, super_classes, methods, iann)) -> - Some type_name - | _ -> None - -let resolve_method tenv class_name method_name = - let class_name_mangled = Mangled.from_string class_name in - match resolve_method_class tenv class_name_mangled method_name with - | Some (Sil.TN_csu (Sil.Class, class_name)) -> - let class_method_name = mk_procname_from_method (Mangled.to_string class_name) method_name in - (try let ms = CMethod_signature.find class_method_name in - Some ms - with Not_found -> None) - | _ -> None +let mk_procname_from_method class_name method_name method_kind = + let mangled = Procname.mangled_of_objc_method_kind method_kind in + Procname.mangled_c_method class_name method_name mangled let get_superclass_curr_class context = let retrive_super cname super_opt = diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index 5d0e3425a..5fb6fd30d 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -27,13 +27,11 @@ val create_external_procdesc : Cfg.cfg -> Procname.t -> bool -> (Sil.typ * Sil.t val captured_vars_from_block_info : CContext.t -> Clang_ast_t.block_captured_variable list -> (Mangled.t * Sil.typ * bool) list -val mk_procname_from_method : string -> string -> Procname.t +val mk_procname_from_method : string -> string -> Procname.objc_method_kind -> Procname.t val mk_procname_from_function : string -> string -> Procname.t val get_class_selector_instance : CContext.t -> Clang_ast_t.obj_c_message_expr_info -> (Sil.exp * Sil.typ) list -> (string * string * method_call_type) -val resolve_method : Sil.tenv -> string -> string -> CMethod_signature.method_signature option - val should_create_procdesc : Cfg.cfg -> Procname.t -> bool -> bool -> bool diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 2508c817e..4524ab16c 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -43,23 +43,23 @@ struct let (class_name, method_name, mc_type) = CMethod_trans.get_class_selector_instance context obj_c_message_expr_info act_params in let is_instance = mc_type != CMethod_trans.MCStatic in + let method_kind = Procname.objc_method_kind_of_bool is_instance in match CTrans_models.get_predefined_model_method_signature class_name method_name CMethod_trans.mk_procname_from_method with | Some ms -> ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv ms [] [] is_instance); CMethod_signature.ms_get_name ms, CMethod_trans.MCNoVirtual | None -> - match CMethod_trans.resolve_method context.tenv class_name method_name with - | Some callee_ms -> - (let procname = CMethod_signature.ms_get_name callee_ms in - if not (M.process_getter_setter context procname) then - (let is_instance = is_instance || (CMethod_signature.ms_is_instance callee_ms) in - ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] is_instance)); - procname, mc_type) - | None -> - let callee_pn = CMethod_trans.mk_procname_from_method class_name method_name in - CMethod_trans.create_external_procdesc context.cfg callee_pn is_instance None; - callee_pn, mc_type + let procname = CMethod_trans.mk_procname_from_method class_name method_name method_kind in + try + let callee_ms = CMethod_signature.find procname in + if not (M.process_getter_setter context procname) then + (ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv callee_ms [] [] is_instance)); + procname, mc_type + with Not_found -> + let callee_pn = CMethod_trans.mk_procname_from_method class_name method_name method_kind in + CMethod_trans.create_external_procdesc context.cfg callee_pn is_instance None; + callee_pn, mc_type let add_autorelease_call context exp typ sil_loc = let method_name = Procname.c_get_method (Cfg.Procdesc.get_proc_name context.procdesc) in diff --git a/infer/src/clang/cTrans_models.ml b/infer/src/clang/cTrans_models.ml index e25051c8e..bcedb210a 100644 --- a/infer/src/clang/cTrans_models.ml +++ b/infer/src/clang/cTrans_models.ml @@ -121,13 +121,13 @@ let is_assert_log sil_fe = let is_objc_memory_model_controlled o = Core_foundation_model.is_objc_memory_model_controlled o -let get_predefined_ms_method condition class_name method_name mk_procname +let get_predefined_ms_method condition class_name method_name method_kind mk_procname arguments return_type attributes builtin = if condition then let procname = match builtin with | Some procname -> procname - | None -> mk_procname class_name method_name in + | None -> mk_procname class_name method_name method_kind in let ms = CMethod_signature.make_ms procname arguments return_type attributes (Ast_expressions.dummy_source_range ()) false false in Some ms @@ -135,26 +135,27 @@ let get_predefined_ms_method condition class_name method_name mk_procname let get_predefined_ms_stringWithUTF8String class_name method_name mk_procname = let condition = class_name = nsstring_cl && method_name = string_with_utf8_m in - get_predefined_ms_method condition class_name method_name mk_procname [("x", "char *", None)] - id_cl [] None + get_predefined_ms_method condition class_name method_name Procname.Class_objc_method + mk_procname [("x", "char *", None)] id_cl [] None let get_predefined_ms_retain_release class_name method_name mk_procname = let condition = is_retain_or_release method_name in let return_type = if is_retain_method method_name || is_autorelease_method method_name then id_cl else void in - get_predefined_ms_method condition nsobject_cl method_name mk_procname - [(self, class_name, None)] return_type [] (get_builtinname method_name) + get_predefined_ms_method condition nsobject_cl method_name Procname.Instance_objc_method + mk_procname [(self, class_name, None)] return_type [] (get_builtinname method_name) let get_predefined_ms_autoreleasepool_init class_name method_name mk_procname = let condition = (method_name = init) && (class_name = nsautorelease_pool_cl) in - get_predefined_ms_method condition class_name method_name mk_procname - [(self, class_name, None)] void [] None + get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method + mk_procname [(self, class_name, None)] void [] None let get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procname = let condition = (method_name = release || method_name = drain) && (class_name = nsautorelease_pool_cl) in - get_predefined_ms_method condition class_name method_name mk_procname [(self, class_name, None)] + get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method + mk_procname [(self, class_name, None)] void [] (Some SymExec.ModelBuiltins.__objc_release_autorelease_pool) let get_predefined_model_method_signature class_name method_name mk_procname = diff --git a/infer/src/clang/cTrans_models.mli b/infer/src/clang/cTrans_models.mli index 856951152..9105e2755 100644 --- a/infer/src/clang/cTrans_models.mli +++ b/infer/src/clang/cTrans_models.mli @@ -25,7 +25,8 @@ val is_modeled_builtin : string -> bool val is_toll_free_bridging : Procname.t option -> bool -val get_predefined_model_method_signature : string -> string -> (string -> string -> Procname.t) -> +val get_predefined_model_method_signature : string -> string -> + (string -> string -> Procname.objc_method_kind -> Procname.t) -> CMethod_signature.method_signature option val is_dispatch_function_name : string -> (string * int) option diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index 5f13d17d7..533b82399 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -303,7 +303,7 @@ let new_trans trans_state loc stmt_info cls_name function_type = let init_ret_id = Ident.create_fresh Ident.knormal in let is_instance = true in let call_flags = { Sil.cf_virtual = is_instance; Sil.cf_noreturn = false; Sil.cf_is_objc_block = false; } in - let pname = CMethod_trans.mk_procname_from_method cls_name CFrontend_config.init in + let pname = CMethod_trans.mk_procname_from_method cls_name CFrontend_config.init Procname.Instance_objc_method in CMethod_trans.create_external_procdesc trans_state.context.cfg pname is_instance None; let args = [(Sil.Var alloc_ret_id, alloc_ret_type)] in let init_stmt_call = Sil.Call([init_ret_id], (Sil.Const (Sil.Cfun pname)), args, loc, call_flags) in diff --git a/infer/src/clang/objcProperty_decl.ml b/infer/src/clang/objcProperty_decl.ml index d69dbf891..0c6923856 100644 --- a/infer/src/clang/objcProperty_decl.ml +++ b/infer/src/clang/objcProperty_decl.ml @@ -243,15 +243,6 @@ let prepare_dynamic_property curr_class decl_info property_impl_decl_info = (* No names of fields/method to collect from ObjCPropertyImplDecl when Synthesized *) [] -(*NOTE: Assumption: if there is a getter or a setter defined manually, *) -(* it has been translated already at this point. *) -let method_exists cfg class_name name attributes = - let procname = CMethod_trans.mk_procname_from_method class_name name in - match Cfg.Procdesc.find_from_name cfg procname with - | Some procdesc -> - Cfg.Procdesc.is_defined procdesc - | None -> false - let is_property_read_only attributes = list_mem (Ast_utils.property_attribute_eq) `Readonly attributes @@ -374,10 +365,12 @@ let get_methods curr_class decl_list = let get_method decl list_methods = match decl with ObjCMethodDecl(decl_info, name_info, method_decl_info) as d -> + let is_instance = method_decl_info.Clang_ast_t.omdi_is_instance_method in + let method_kind = Procname.objc_method_kind_of_bool is_instance in let method_name = name_info.Clang_ast_t.ni_name in Printing.log_out " ...Adding Method '%s' \n" (class_name^"_"^method_name); let _ = check_for_property curr_class method_name d method_decl_info.Clang_ast_t.omdi_body in - let meth_name = CMethod_trans.mk_procname_from_method class_name method_name in + let meth_name = CMethod_trans.mk_procname_from_method class_name method_name method_kind in meth_name:: list_methods | _ -> list_methods in list_fold_right get_method decl_list [] diff --git a/infer/tests/codetoanalyze/objc/errors/npe/Npe_with_equal_names.m b/infer/tests/codetoanalyze/objc/errors/npe/Npe_with_equal_names.m new file mode 100644 index 000000000..58ea718d1 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/errors/npe/Npe_with_equal_names.m @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2014 - 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 { + @public int x; +} + ++(A*) meth; + +@property (nonatomic, readonly) A* meth; + +@end + +@implementation A + ++(A*) meth { + return [A new]; +} + +-(A*) meth { + return nil; +} + +@end + +int test() { + A* para = [A new]; + A *a = [para meth]; + return a->x; +} + +int test2(A* para) { + A *a = [A meth]; + return a->x; +} diff --git a/infer/tests/endtoend/objc/NPEEqualNamesTest.java b/infer/tests/endtoend/objc/NPEEqualNamesTest.java new file mode 100644 index 000000000..82d8f40ab --- /dev/null +++ b/infer/tests/endtoend/objc/NPEEqualNamesTest.java @@ -0,0 +1,68 @@ +/* +* Copyright (c) 2013 - 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. +*/ + +package endtoend.objc; + +import static org.hamcrest.MatcherAssert.assertThat; +import static utils.matchers.ResultContainsExactly.containsExactly; +import static utils.matchers.ResultContainsNoErrorInMethod.doesNotContain; +import static utils.matchers.ResultContainsErrorInMethod.contains; + +import com.google.common.collect.ImmutableList; + +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; + +import utils.DebuggableTemporaryFolder; +import utils.InferException; +import utils.InferResults; +import utils.InferRunner; + +public class NPEEqualNamesTest { + + public static final String NPE_FILE = + "infer/tests/codetoanalyze/objc/errors/npe/Npe_with_equal_names.m"; + + private static ImmutableList inferCmdNPD; + + public static final String NULL_DEREFERENCE = "NULL_DEREFERENCE"; + + @ClassRule + public static DebuggableTemporaryFolder folderNPD = new DebuggableTemporaryFolder(); + + @BeforeClass + public static void runInfer() throws InterruptedException, IOException { + inferCmdNPD = InferRunner.createiOSInferCommandWithMLBuckets( + folderNPD, + NPE_FILE, + "cf", + false); + } + + @Test + public void nullDereferenceTest() throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferObjC(inferCmdNPD); + String[] procedures = { + "test", + }; + assertThat( + "Results should contain null pointer dereference error", + inferResults, + containsExactly( + NULL_DEREFERENCE, + NPE_FILE, + procedures + ) + ); + } + +}