From d73d4ea177c61e567bf0a37ebd19761237350409 Mon Sep 17 00:00:00 2001 From: Dulma Churchill Date: Wed, 11 May 2016 08:06:30 -0700 Subject: [PATCH] Getting a more precise type when creating ObjC objects Reviewed By: ddino Differential Revision: D3282402 fbshipit-source-id: 4a57c9c --- infer/src/IR/attributesTable.ml | 22 ++++++++++++++++++++++ infer/src/IR/attributesTable.mli | 9 +++++++++ infer/src/IR/procname.ml | 4 ++++ infer/src/IR/procname.mli | 2 ++ infer/src/backend/modelBuiltins.ml | 7 +++++++ infer/src/clang/cFrontend_decl.ml | 4 +++- infer/src/clang/cMethod_trans.ml | 6 ++++++ infer/src/clang/cMethod_trans.mli | 2 ++ 8 files changed, 55 insertions(+), 1 deletion(-) diff --git a/infer/src/IR/attributesTable.ml b/infer/src/IR/attributesTable.ml index 4a5bc2c97..e5edacb5f 100644 --- a/infer/src/IR/attributesTable.ml +++ b/infer/src/IR/attributesTable.ml @@ -49,3 +49,25 @@ let store_attributes proc_attributes = let load_attributes proc_name = let attributes_file = res_dir_attr_filename proc_name in Serialization.from_file serializer attributes_file + +(** Given a procdesure name, find the file where it is defined and *) +(** its corresponding type environment *) +let find_tenv_from_class_of_proc procname = + match load_attributes procname with + | None -> None + | Some attrs -> + let source_file = attrs.ProcAttributes.loc.Location.file in + let source_dir = DB.source_dir_from_source_file source_file in + let tenv_fname = DB.source_dir_get_internal_file source_dir ".tenv" in + Tenv.load_from_file tenv_fname + +(** Given an ObjC class c, extract the type from the tenv where the class was *) +(** defined. We do this by adding a method that is unique to each class, and then *) +(** finding the tenv that corresponds to the class definition. *) +let get_correct_type_from_objc_class_name c = + let class_method = Procname.get_default_objc_class_method (Mangled.to_string c) in + match find_tenv_from_class_of_proc class_method with + | None -> None + | Some tenv -> + let type_name = Typename.TN_csu (Csu.Class Csu.Objc, c) in + Option.map (fun st -> Sil.Tstruct st) (Tenv.lookup tenv type_name) diff --git a/infer/src/IR/attributesTable.mli b/infer/src/IR/attributesTable.mli index 4203940a6..eed79607f 100644 --- a/infer/src/IR/attributesTable.mli +++ b/infer/src/IR/attributesTable.mli @@ -17,3 +17,12 @@ val store_attributes : ProcAttributes.t -> unit (** Load the attributes for the procedure from the attributes database. *) val load_attributes : Procname.t -> ProcAttributes.t option + +(** Given a procdesure name, find the file where it is defined and *) +(** its corresponding type environment *) +val find_tenv_from_class_of_proc : Procname.t -> Tenv.t option + +(** Given an ObjC class c, extract the type from the tenv where the class was *) +(** defined. We do this by adding a method that is unique to each class, and then *) +(** finding the tenv that corresponds to the class definition. *) +val get_correct_type_from_objc_class_name : Mangled.t -> Sil.typ option diff --git a/infer/src/IR/procname.ml b/infer/src/IR/procname.ml index 2d295b12b..7bd6dccbb 100644 --- a/infer/src/IR/procname.ml +++ b/infer/src/IR/procname.ml @@ -182,6 +182,10 @@ let objc_cpp class_name method_name mangled = mangled = mangled; } +let get_default_objc_class_method objc_class = + let objc_cpp = objc_cpp objc_class "__find_class_" (Some "internal") in + ObjC_Cpp objc_cpp + (** Create an objc procedure name from a class_name and method_name. *) let mangled_objc_block name = Block name diff --git a/infer/src/IR/procname.mli b/infer/src/IR/procname.mli index 397bb3226..2e6682479 100644 --- a/infer/src/IR/procname.mli +++ b/infer/src/IR/procname.mli @@ -108,6 +108,8 @@ val mangled_of_objc_method_kind : objc_method_kind -> string option (** Create an objc procedure name from a class_name and method_name. *) val objc_cpp : string -> string -> string option -> objc_cpp +val get_default_objc_class_method : string -> t + (** Get the class name of a Objective-C/C++ procedure name. *) val objc_cpp_get_class_name : objc_cpp -> string diff --git a/infer/src/backend/modelBuiltins.ml b/infer/src/backend/modelBuiltins.ml index 1f164cdc0..a47cee20e 100644 --- a/infer/src/backend/modelBuiltins.ml +++ b/infer/src/backend/modelBuiltins.ml @@ -770,6 +770,13 @@ let execute_alloc mk can_return_null let handle_sizeof_exp size_exp = Sil.Sizeof (Sil.Tarray (Sil.Tint Sil.IChar, size_exp), Sil.Subtype.exact) in let size_exp, procname = match args with + | [(Sil.Sizeof (Sil.Tstruct + { Sil.csu = Csu.Class Csu.Objc; struct_name = Some c } as s, subt), _)] -> + let struct_type = + match AttributesTable.get_correct_type_from_objc_class_name c with + | Some struct_type -> struct_type + | None -> s in + Sil.Sizeof (struct_type, subt), pname | [(size_exp, _)] -> (* for malloc and __new *) size_exp, Sil.mem_alloc_pname mk | [(size_exp, _); (Sil.Const (Sil.Cfun pname), _)] -> diff --git a/infer/src/clang/cFrontend_decl.ml b/infer/src/clang/cFrontend_decl.ml index a3062098f..e1b1d00fb 100644 --- a/infer/src/clang/cFrontend_decl.ml +++ b/infer/src/clang/cFrontend_decl.ml @@ -166,10 +166,12 @@ struct ignore (ObjcCategory_decl.category_impl_decl CTypes_decl.type_ptr_to_sil_type tenv dec); process_methods tenv cg cfg curr_class decl_list; - | ObjCImplementationDecl(_, _, decl_list, _, idi) -> + | ObjCImplementationDecl(decl_info, _, decl_list, _, idi) -> let curr_class = ObjcInterface_decl.get_curr_class_impl idi in + let class_name = CContext.get_curr_class_name curr_class in let type_ptr_to_sil_type = CTypes_decl.type_ptr_to_sil_type in ignore (ObjcInterface_decl.interface_impl_declaration type_ptr_to_sil_type tenv dec); + CMethod_trans.add_default_method_for_class class_name decl_info; process_methods tenv cg cfg curr_class decl_list; | CXXMethodDecl (decl_info, _, _, _, _) diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 9b3f5c1f2..001bc4ba5 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -462,6 +462,12 @@ let get_method_for_frontend_checks cfg cg loc = Cg.add_defined_node cg proc_name; pdesc +let add_default_method_for_class class_name decl_info = + let loc = CLocation.get_sil_location_from_range decl_info.Clang_ast_t.di_source_range true in + let proc_name = Procname.get_default_objc_class_method class_name in + let attrs = { (ProcAttributes.default proc_name Config.C_CPP) with loc = loc; } in + AttributesTable.store_attributes attrs + let get_procname_from_cpp_lambda context dec = match dec with | Clang_ast_t.CXXRecordDecl (_, _, _, _, _, _, _, cxx_rdi) -> diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index 8a2c6ce7f..84aa8b448 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -52,4 +52,6 @@ val create_procdesc_with_pointer : CContext.t -> Clang_ast_t.pointer -> string o val get_method_for_frontend_checks : Cfg.cfg -> Cg.t -> Location.t -> Cfg.Procdesc.t +val add_default_method_for_class : string -> Clang_ast_t.decl_info -> unit + val get_procname_from_cpp_lambda : CContext.t -> Clang_ast_t.decl -> Procname.t