From b8044c6b6530919601dc2be6eb2ff371d3437c39 Mon Sep 17 00:00:00 2001 From: Andrzej Kotulski Date: Mon, 18 Jul 2016 07:42:12 -0700 Subject: [PATCH] Use mangled names instead of function type for mangling Summary: Use Itanium mangling for C++ functions/methods instead of raw type name. This is a step towards removing expensive `ti_raw` field from `type_info`. For virtual methods, use mangled name of the method from base class in order for dynamic dispatch to work. Reviewed By: dulmarod Differential Revision: D3556118 fbshipit-source-id: e45edb5 --- facebook-clang-plugins | 2 +- infer/models/c/src/libc_basic.c | 35 ++++++++++-------- infer/models/cpp/Makefile | 3 +- infer/src/clang/cFrontend_utils.ml | 56 ++++++++++++++++++----------- infer/src/clang/cFrontend_utils.mli | 7 ++-- infer/src/clang/cMethod_trans.ml | 15 ++++---- infer/src/clang/cMethod_trans.mli | 2 +- infer/src/clang/cTrans.ml | 4 +-- infer/src/clang/cTypes_decl.ml | 13 +++---- 9 files changed, 82 insertions(+), 55 deletions(-) diff --git a/facebook-clang-plugins b/facebook-clang-plugins index 155fb6d52..eb8d2109d 160000 --- a/facebook-clang-plugins +++ b/facebook-clang-plugins @@ -1 +1 @@ -Subproject commit 155fb6d52891843b14c3837083aeb492b7b20d16 +Subproject commit eb8d2109d769822ee1915a54e6be1cfb7e3fe99b diff --git a/infer/models/c/src/libc_basic.c b/infer/models/c/src/libc_basic.c index d3af81da7..cb88d989e 100644 --- a/infer/models/c/src/libc_basic.c +++ b/infer/models/c/src/libc_basic.c @@ -17,8 +17,6 @@ #endif #define _FORTIFY_SOURCE 0 -#define __asm(N) - #ifdef __APPLE__ // disable block instructions on mac #ifdef __BLOCKS__ #undef __BLOCKS__ @@ -136,7 +134,14 @@ char* strcat(char* s1, const char* s2) { #ifndef __CORRECT_ISO_CPP_STRING_H_PROTO char* strchr(const char* s, int c) { #else -const char* strchr(const char* s, int c) throw() { return strchr((char*)s, c); } +// This overload is commented out on purpose. +// Standard headers define both functions with same __asm symbol which +// means they cannot be both defined. On the other hand, since both of them +// have same __asm symbol, mangling will be the same and infer will have +// specs for both functions (they both will have the same name) +// NOTE: this was tested on couple of systems, it may not be always true. +// const char* strchr(const char* s, int c) throw() { return strchr((char*)s, +// c); } char* strchr(char* s, int c) throw() { #endif @@ -158,9 +163,10 @@ char* strchr(char* s, int c) throw() { #ifndef __CORRECT_ISO_CPP_STRING_H_PROTO char* strrchr(const char* s, int c) { return strchr(s, c); } #else -const char* strrchr(const char* s, int c) throw() { +// This overload is commented out on purpose. Look at strchr() for more info. +/*const char* strrchr(const char* s, int c) throw() { return strchr((char*)s, c); -} +}*/ char* strrchr(char* s, int c) throw() { return strchr(s, c); } #endif @@ -239,9 +245,10 @@ char* strncpy(char* s1, const char* s2, size_t n) { #ifndef __CORRECT_ISO_CPP_STRING_H_PROTO char* strpbrk(const char* s1, const char* s2) { #else -const char* strpbrk(const char* s1, const char* s2) throw() { +// This overload is commented out on purpose. Look at strchr() for more info. +/*const char* strpbrk(const char* s1, const char* s2) throw() { return strpbrk((char*)s1, s2); -} +}*/ char* strpbrk(char* s1, const char* s2) throw() { #endif @@ -275,10 +282,10 @@ size_t strspn(const char* s1, const char* s2) { #ifndef __CORRECT_ISO_CPP_STRING_H_PROTO char* strstr(const char* s1, const char* s2) { #else - -const char* strstr(const char* s1, const char* s2) throw() { +// This overload is commented out on purpose. Look at strchr() for more info. +/*const char* strstr(const char* s1, const char* s2) throw() { return strstr((char*)s1, s2); -} +}*/ char* strstr(char* s1, const char* s2) throw() { #endif @@ -339,10 +346,10 @@ char* strupr(char* s) { #ifndef __CORRECT_ISO_CPP_STRING_H_PROTO void* memchr(const void* s, int c, size_t n) { #else - -const void* memchr(const void* s, int c, size_t n) throw() { - return memchr((void*)s, c, n); -} +// This overload is commented out on purpose. Look at strchr() for more info. +// const void* memchr(const void* s, int c, size_t n) throw() { +// return memchr((void*)s, c, n); +//} void* memchr(void* s, int c, size_t n) throw() { #endif diff --git a/infer/models/cpp/Makefile b/infer/models/cpp/Makefile index ff6a4db58..d6bce6fa9 100644 --- a/infer/models/cpp/Makefile +++ b/infer/models/cpp/Makefile @@ -10,12 +10,13 @@ include $(ROOT_DIR)/Makefile.config CPP_MODELS_FILE = $(SPECS_LIB_DIR)/cpp_models CPP_MODELS_SOURCES = $(shell find src/ -name "*.cpp") +C_MODELS_SOURCES = $(shell find src/c_src/ -name "*.c") INFER = INFER_ANALYZE_MODELS=1 $(BIN_DIR)/infer all: $(CPP_MODELS_FILE) -$(CPP_MODELS_FILE): $(CPP_MODELS_SOURCES) $(CLANG_DEPS) +$(CPP_MODELS_FILE): $(CPP_MODELS_SOURCES) $(C_MODELS_SOURCES) $(CLANG_DEPS) # make clean in src/ in case $(CLANG_DEPS) have changed $(MAKE) -C src clean $(INFER) -o out/ --models_mode --no_failures_allowed --cxx -- $(MAKE) -C src diff --git a/infer/src/clang/cFrontend_utils.ml b/infer/src/clang/cFrontend_utils.ml index 608334594..6aa965063 100644 --- a/infer/src/clang/cFrontend_utils.ml +++ b/infer/src/clang/cFrontend_utils.ml @@ -585,7 +585,30 @@ struct | None -> file) | None -> "" - let mk_procname_from_function name function_decl_info_opt tp language = + let is_cpp_translation language = + language = Config.CPP || language = Config.OBJCPP + + let rec get_mangled_method_name function_decl_info method_decl_info = + (* For virtual methods return mangled name of the method from most base class + Go recursively until there is no method in any parent class. All names + of the same method need to be the same, otherwise dynamic dispatch won't + work. *) + let open Clang_ast_t in + match method_decl_info.xmdi_overriden_methods with + | [] -> function_decl_info.fdi_mangled_name + | base1_dr :: _ -> + (let base1 = match Ast_utils.get_decl base1_dr.dr_decl_pointer with + | Some b -> b + | _ -> assert false in + match base1 with + | CXXMethodDecl (_, _, _, fdi, mdi) + | CXXConstructorDecl (_, _, _, fdi, mdi) + | CXXConversionDecl (_, _, _, fdi, mdi) + | CXXDestructorDecl (_, _, _, fdi, mdi) -> + get_mangled_method_name fdi mdi + | _ -> assert false) + + let mk_procname_from_function name function_decl_info_opt language = let file = match function_decl_info_opt with | Some (decl_info, function_decl_info) -> @@ -595,33 +618,27 @@ struct get_rel_file_path file_opt | _ -> "") | None -> "" in - let type_string = - match language with - | Config.CPP - | Config.OBJCPP -> Ast_utils.string_of_type_ptr tp + let mangled_opt = match function_decl_info_opt with + | Some (_, function_decl_info) -> function_decl_info.Clang_ast_t.fdi_mangled_name + | _ -> None in + let mangled_name = + match mangled_opt with + | Some m when is_cpp_translation language -> m | _ -> "" in - (* remove __restrict from type name to avoid mismatches. Clang allows to declare function*) - (* with __restrict parameters and then define it without (it mostly applies to models).*) - (* We are not using this information right now so we can remove it to avoid dealing with*) - (* corner cases on different systems *) - let type_string_no_restrict = Str.global_replace (Str.regexp "__restrict") "" type_string in - let mangled = file ^ type_string_no_restrict in - if String.length mangled == 0 then + let mangled = (string_crc_hex32 file) ^ mangled_name in + if String.length file == 0 && String.length mangled_name == 0 then Procname.from_string_c_fun name else - let crc = string_crc_hex32 mangled in - Procname.C (Procname.c name crc) + Procname.C (Procname.c name mangled) let mk_procname_from_objc_method class_name method_name method_kind = let mangled = Procname.mangled_of_objc_method_kind method_kind in Procname.ObjC_Cpp (Procname.objc_cpp class_name method_name mangled) - let mk_procname_from_cpp_method class_name method_name tp = - let type_name = Ast_utils.string_of_type_ptr tp in - let type_name_crc = Some (string_crc_hex32 type_name) in + let mk_procname_from_cpp_method class_name method_name mangled_opt = Procname.ObjC_Cpp - (Procname.objc_cpp class_name method_name type_name_crc) + (Procname.objc_cpp class_name method_name mangled_opt) let get_var_name_mangled name_info var_decl_info = let clang_name = Ast_utils.get_qualified_name name_info in @@ -658,7 +675,4 @@ struct Pvar.mk mangled_name procname | None -> Pvar.mk (Mangled.from_string name_string) procname - let is_cpp_translation language = - language = Config.CPP || language = Config.OBJCPP - end diff --git a/infer/src/clang/cFrontend_utils.mli b/infer/src/clang/cFrontend_utils.mli index 527081a74..3a4e3eb62 100644 --- a/infer/src/clang/cFrontend_utils.mli +++ b/infer/src/clang/cFrontend_utils.mli @@ -202,9 +202,12 @@ sig val mk_procname_from_objc_method : string -> string -> Procname.objc_method_kind -> Procname.t val mk_procname_from_function : string -> (Clang_ast_t.decl_info * Clang_ast_t.function_decl_info) - option -> Clang_ast_t.type_ptr -> Config.clang_lang -> Procname.t + option -> Config.clang_lang -> Procname.t - val mk_procname_from_cpp_method : string -> string -> Clang_ast_t.type_ptr -> Procname.t + val get_mangled_method_name : Clang_ast_t.function_decl_info -> + Clang_ast_t.cxx_method_decl_info -> string option + + val mk_procname_from_cpp_method : string -> string -> string option-> Procname.t val mk_class_field_name : Clang_ast_t.named_decl_info -> Ident.fieldname diff --git a/infer/src/clang/cMethod_trans.ml b/infer/src/clang/cMethod_trans.ml index 07b1d6131..d6ff9fa9a 100644 --- a/infer/src/clang/cMethod_trans.ml +++ b/infer/src/clang/cMethod_trans.ml @@ -170,7 +170,7 @@ let method_signature_of_decl tenv meth_decl block_data_opt = let language = Config.clang_lang in let func_decl = Func_decl_info (fdi, tp, language) in let function_info = Some (decl_info, fdi) in - let procname = General_utils.mk_procname_from_function name function_info tp language in + let procname = General_utils.mk_procname_from_function name function_info language in let ms = build_method_signature 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 @@ -180,7 +180,8 @@ let method_signature_of_decl tenv meth_decl block_data_opt = | CXXDestructorDecl (decl_info, name_info, tp, fdi, mdi), _ -> let method_name = Ast_utils.get_unqualified_name name_info in let class_name = Ast_utils.get_class_name_from_member name_info in - let procname = General_utils.mk_procname_from_cpp_method class_name method_name tp in + let mangled = General_utils.get_mangled_method_name fdi mdi in + let procname = General_utils.mk_procname_from_cpp_method class_name method_name mangled in let parent_ptr = Option.get decl_info.di_parent_pointer in let method_decl = Cpp_Meth_decl_info (fdi, mdi, parent_ptr, tp) in let parent_pointer = decl_info.Clang_ast_t.di_parent_pointer in @@ -433,7 +434,7 @@ let create_external_procdesc cfg proc_name is_objc_inst_method type_opt = } in ignore (Cfg.Procdesc.create cfg proc_attributes) -let create_procdesc_with_pointer context pointer class_name_opt name tp = +let create_procdesc_with_pointer context pointer class_name_opt name = let open CContext in match method_signature_of_pointer context.tenv pointer with | Some callee_ms -> @@ -443,9 +444,9 @@ let create_procdesc_with_pointer context pointer class_name_opt name tp = let callee_name = match class_name_opt with | Some class_name -> - General_utils.mk_procname_from_cpp_method class_name name tp + General_utils.mk_procname_from_cpp_method class_name name None | None -> - General_utils.mk_procname_from_function name None tp Config.clang_lang in + General_utils.mk_procname_from_function name None Config.clang_lang in create_external_procdesc context.cfg callee_name false None; callee_name @@ -479,8 +480,8 @@ let get_procname_from_cpp_lambda context dec = | Clang_ast_t.CXXRecordDecl (_, _, _, _, _, _, _, cxx_rdi) -> (match cxx_rdi.xrdi_lambda_call_operator with | Some dr -> - let name_info, decl_ptr, type_ptr = Ast_utils.get_info_from_decl_ref dr in - create_procdesc_with_pointer context decl_ptr None name_info.ni_name type_ptr + let name_info, decl_ptr, _ = Ast_utils.get_info_from_decl_ref dr in + create_procdesc_with_pointer context decl_ptr None name_info.ni_name | _ -> assert false (* We should not get here *)) | _ -> assert false (* We should not get here *) diff --git a/infer/src/clang/cMethod_trans.mli b/infer/src/clang/cMethod_trans.mli index 1f1e9c153..1df395255 100644 --- a/infer/src/clang/cMethod_trans.mli +++ b/infer/src/clang/cMethod_trans.mli @@ -48,7 +48,7 @@ val get_method_name_from_clang : Tenv.t -> CMethod_signature.method_signature op CMethod_signature.method_signature option val create_procdesc_with_pointer : CContext.t -> Clang_ast_t.pointer -> string option -> - string -> Clang_ast_t.type_ptr -> Procname.t + string -> Procname.t val get_method_for_frontend_checks : Cfg.cfg -> Cg.t -> Location.t -> Cfg.Procdesc.t diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index a46a32b47..4bd91a465 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -454,7 +454,7 @@ struct let pname = if CTrans_models.is_modeled_builtin name then Procname.from_string_c_fun (CFrontend_config.infer ^ name) - else CMethod_trans.create_procdesc_with_pointer context decl_ptr None name type_ptr in + else CMethod_trans.create_procdesc_with_pointer context decl_ptr None name in let address_of_function = not context.CContext.is_callee_expression in (* If we are not translating a callee expression, *) (* then the address of the function is being taken.*) @@ -587,7 +587,7 @@ struct (* consider using context.CContext.is_callee_expression to deal with pointers to methods? *) (* unlike field access, for method calls there is no need to expand class type *) let pname = CMethod_trans.create_procdesc_with_pointer context decl_ptr (Some class_name) - method_name type_ptr in + method_name in let method_exp = (Sil.Const (Const.Cfun pname), method_typ) in Cfg.set_procname_priority context.CContext.cfg pname; { pre_trans_result with diff --git a/infer/src/clang/cTypes_decl.ml b/infer/src/clang/cTypes_decl.ml index ffe4b4f2c..475284af6 100644 --- a/infer/src/clang/cTypes_decl.ml +++ b/infer/src/clang/cTypes_decl.ml @@ -104,14 +104,15 @@ let get_record_name decl = snd (get_record_name_csu decl) let get_class_methods class_name decl_list = let process_method_decl = function - | Clang_ast_t.CXXMethodDecl (_, name_info, tp, _, _) - | Clang_ast_t.CXXConstructorDecl (_, name_info, tp, _, _) - | Clang_ast_t.CXXConversionDecl (_, name_info, tp, _, _) - | Clang_ast_t.CXXDestructorDecl (_, name_info, tp, _, _) -> + | Clang_ast_t.CXXMethodDecl (_, name_info, _, fdi, mdi) + | Clang_ast_t.CXXConstructorDecl (_, name_info, _, fdi, mdi) + | Clang_ast_t.CXXConversionDecl (_, name_info, _, fdi, mdi) + | Clang_ast_t.CXXDestructorDecl (_, name_info, _, fdi, mdi) -> let method_name = name_info.Clang_ast_t.ni_name in Printing.log_out " ...Declaring method '%s'.\n" method_name; - let method_proc = General_utils.mk_procname_from_cpp_method class_name method_name tp in - Some method_proc + let mangled = General_utils.get_mangled_method_name fdi mdi in + let procname = General_utils.mk_procname_from_cpp_method class_name method_name mangled in + Some procname | _ -> None in (* poor mans list_filter_map *) IList.flatten_options (IList.map process_method_decl decl_list)