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
master
Andrzej Kotulski 9 years ago committed by Facebook Github Bot 1
parent d946a7bc33
commit b8044c6b65

@ -1 +1 @@
Subproject commit 155fb6d52891843b14c3837083aeb492b7b20d16 Subproject commit eb8d2109d769822ee1915a54e6be1cfb7e3fe99b

@ -17,8 +17,6 @@
#endif #endif
#define _FORTIFY_SOURCE 0 #define _FORTIFY_SOURCE 0
#define __asm(N)
#ifdef __APPLE__ // disable block instructions on mac #ifdef __APPLE__ // disable block instructions on mac
#ifdef __BLOCKS__ #ifdef __BLOCKS__
#undef __BLOCKS__ #undef __BLOCKS__
@ -136,7 +134,14 @@ char* strcat(char* s1, const char* s2) {
#ifndef __CORRECT_ISO_CPP_STRING_H_PROTO #ifndef __CORRECT_ISO_CPP_STRING_H_PROTO
char* strchr(const char* s, int c) { char* strchr(const char* s, int c) {
#else #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() { char* strchr(char* s, int c) throw() {
#endif #endif
@ -158,9 +163,10 @@ char* strchr(char* s, int c) throw() {
#ifndef __CORRECT_ISO_CPP_STRING_H_PROTO #ifndef __CORRECT_ISO_CPP_STRING_H_PROTO
char* strrchr(const char* s, int c) { return strchr(s, c); } char* strrchr(const char* s, int c) { return strchr(s, c); }
#else #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); return strchr((char*)s, c);
} }*/
char* strrchr(char* s, int c) throw() { return strchr(s, c); } char* strrchr(char* s, int c) throw() { return strchr(s, c); }
#endif #endif
@ -239,9 +245,10 @@ char* strncpy(char* s1, const char* s2, size_t n) {
#ifndef __CORRECT_ISO_CPP_STRING_H_PROTO #ifndef __CORRECT_ISO_CPP_STRING_H_PROTO
char* strpbrk(const char* s1, const char* s2) { char* strpbrk(const char* s1, const char* s2) {
#else #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); return strpbrk((char*)s1, s2);
} }*/
char* strpbrk(char* s1, const char* s2) throw() { char* strpbrk(char* s1, const char* s2) throw() {
#endif #endif
@ -275,10 +282,10 @@ size_t strspn(const char* s1, const char* s2) {
#ifndef __CORRECT_ISO_CPP_STRING_H_PROTO #ifndef __CORRECT_ISO_CPP_STRING_H_PROTO
char* strstr(const char* s1, const char* s2) { char* strstr(const char* s1, const char* s2) {
#else #else
// This overload is commented out on purpose. Look at strchr() for more info.
const char* strstr(const char* s1, const char* s2) throw() { /*const char* strstr(const char* s1, const char* s2) throw() {
return strstr((char*)s1, s2); return strstr((char*)s1, s2);
} }*/
char* strstr(char* s1, const char* s2) throw() { char* strstr(char* s1, const char* s2) throw() {
#endif #endif
@ -339,10 +346,10 @@ char* strupr(char* s) {
#ifndef __CORRECT_ISO_CPP_STRING_H_PROTO #ifndef __CORRECT_ISO_CPP_STRING_H_PROTO
void* memchr(const void* s, int c, size_t n) { void* memchr(const void* s, int c, size_t n) {
#else #else
// 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() { // const void* memchr(const void* s, int c, size_t n) throw() {
return memchr((void*)s, c, n); // return memchr((void*)s, c, n);
} //}
void* memchr(void* s, int c, size_t n) throw() { void* memchr(void* s, int c, size_t n) throw() {
#endif #endif

@ -10,12 +10,13 @@ include $(ROOT_DIR)/Makefile.config
CPP_MODELS_FILE = $(SPECS_LIB_DIR)/cpp_models CPP_MODELS_FILE = $(SPECS_LIB_DIR)/cpp_models
CPP_MODELS_SOURCES = $(shell find src/ -name "*.cpp") 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 INFER = INFER_ANALYZE_MODELS=1 $(BIN_DIR)/infer
all: $(CPP_MODELS_FILE) 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 clean in src/ in case $(CLANG_DEPS) have changed
$(MAKE) -C src clean $(MAKE) -C src clean
$(INFER) -o out/ --models_mode --no_failures_allowed --cxx -- $(MAKE) -C src $(INFER) -o out/ --models_mode --no_failures_allowed --cxx -- $(MAKE) -C src

@ -585,7 +585,30 @@ struct
| None -> file) | None -> file)
| None -> "" | 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 = let file =
match function_decl_info_opt with match function_decl_info_opt with
| Some (decl_info, function_decl_info) -> | Some (decl_info, function_decl_info) ->
@ -595,33 +618,27 @@ struct
get_rel_file_path file_opt get_rel_file_path file_opt
| _ -> "") | _ -> "")
| None -> "" in | None -> "" in
let type_string = let mangled_opt = match function_decl_info_opt with
match language with | Some (_, function_decl_info) -> function_decl_info.Clang_ast_t.fdi_mangled_name
| Config.CPP | _ -> None in
| Config.OBJCPP -> Ast_utils.string_of_type_ptr tp let mangled_name =
match mangled_opt with
| Some m when is_cpp_translation language -> m
| _ -> "" in | _ -> "" in
(* remove __restrict from type name to avoid mismatches. Clang allows to declare function*) let mangled = (string_crc_hex32 file) ^ mangled_name in
(* with __restrict parameters and then define it without (it mostly applies to models).*) if String.length file == 0 && String.length mangled_name == 0 then
(* 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
Procname.from_string_c_fun name Procname.from_string_c_fun name
else else
let crc = string_crc_hex32 mangled in Procname.C (Procname.c name mangled)
Procname.C (Procname.c name crc)
let mk_procname_from_objc_method class_name method_name method_kind = let mk_procname_from_objc_method class_name method_name method_kind =
let mangled = Procname.mangled_of_objc_method_kind method_kind in let mangled = Procname.mangled_of_objc_method_kind method_kind in
Procname.ObjC_Cpp Procname.ObjC_Cpp
(Procname.objc_cpp class_name method_name mangled) (Procname.objc_cpp class_name method_name mangled)
let mk_procname_from_cpp_method class_name method_name tp = let mk_procname_from_cpp_method class_name method_name mangled_opt =
let type_name = Ast_utils.string_of_type_ptr tp in
let type_name_crc = Some (string_crc_hex32 type_name) in
Procname.ObjC_Cpp 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 get_var_name_mangled name_info var_decl_info =
let clang_name = Ast_utils.get_qualified_name name_info in let clang_name = Ast_utils.get_qualified_name name_info in
@ -658,7 +675,4 @@ struct
Pvar.mk mangled_name procname Pvar.mk mangled_name procname
| None -> Pvar.mk (Mangled.from_string name_string) procname | None -> Pvar.mk (Mangled.from_string name_string) procname
let is_cpp_translation language =
language = Config.CPP || language = Config.OBJCPP
end end

@ -202,9 +202,12 @@ sig
val mk_procname_from_objc_method : string -> string -> Procname.objc_method_kind -> Procname.t 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) 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 val mk_class_field_name : Clang_ast_t.named_decl_info -> Ident.fieldname

@ -170,7 +170,7 @@ let method_signature_of_decl tenv meth_decl block_data_opt =
let language = Config.clang_lang in let language = Config.clang_lang in
let func_decl = Func_decl_info (fdi, tp, language) in let func_decl = Func_decl_info (fdi, tp, language) in
let function_info = Some (decl_info, fdi) 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 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 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, 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), _ -> | CXXDestructorDecl (decl_info, name_info, tp, fdi, mdi), _ ->
let method_name = Ast_utils.get_unqualified_name name_info in 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 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 parent_ptr = Option.get decl_info.di_parent_pointer in
let method_decl = Cpp_Meth_decl_info (fdi, mdi, parent_ptr, tp) 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 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 } in
ignore (Cfg.Procdesc.create cfg proc_attributes) 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 let open CContext in
match method_signature_of_pointer context.tenv pointer with match method_signature_of_pointer context.tenv pointer with
| Some callee_ms -> | Some callee_ms ->
@ -443,9 +444,9 @@ let create_procdesc_with_pointer context pointer class_name_opt name tp =
let callee_name = let callee_name =
match class_name_opt with match class_name_opt with
| Some class_name -> | 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 -> | 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; create_external_procdesc context.cfg callee_name false None;
callee_name callee_name
@ -479,8 +480,8 @@ let get_procname_from_cpp_lambda context dec =
| Clang_ast_t.CXXRecordDecl (_, _, _, _, _, _, _, cxx_rdi) -> | Clang_ast_t.CXXRecordDecl (_, _, _, _, _, _, _, cxx_rdi) ->
(match cxx_rdi.xrdi_lambda_call_operator with (match cxx_rdi.xrdi_lambda_call_operator with
| Some dr -> | Some dr ->
let name_info, decl_ptr, type_ptr = Ast_utils.get_info_from_decl_ref dr in 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 type_ptr 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 *))
| _ -> assert false (* We should not get here *) | _ -> assert false (* We should not get here *)

@ -48,7 +48,7 @@ val get_method_name_from_clang : Tenv.t -> CMethod_signature.method_signature op
CMethod_signature.method_signature option CMethod_signature.method_signature option
val create_procdesc_with_pointer : CContext.t -> Clang_ast_t.pointer -> string 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 val get_method_for_frontend_checks : Cfg.cfg -> Cg.t -> Location.t -> Cfg.Procdesc.t

@ -454,7 +454,7 @@ struct
let pname = let pname =
if CTrans_models.is_modeled_builtin name then if CTrans_models.is_modeled_builtin name then
Procname.from_string_c_fun (CFrontend_config.infer ^ name) 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 let address_of_function = not context.CContext.is_callee_expression in
(* If we are not translating a callee expression, *) (* If we are not translating a callee expression, *)
(* then the address of the function is being taken.*) (* 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? *) (* 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 *) (* 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) 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 let method_exp = (Sil.Const (Const.Cfun pname), method_typ) in
Cfg.set_procname_priority context.CContext.cfg pname; Cfg.set_procname_priority context.CContext.cfg pname;
{ pre_trans_result with { pre_trans_result with

@ -104,14 +104,15 @@ let get_record_name decl = snd (get_record_name_csu decl)
let get_class_methods class_name decl_list = let get_class_methods class_name decl_list =
let process_method_decl = function let process_method_decl = function
| Clang_ast_t.CXXMethodDecl (_, name_info, tp, _, _) | Clang_ast_t.CXXMethodDecl (_, name_info, _, fdi, mdi)
| Clang_ast_t.CXXConstructorDecl (_, name_info, tp, _, _) | Clang_ast_t.CXXConstructorDecl (_, name_info, _, fdi, mdi)
| Clang_ast_t.CXXConversionDecl (_, name_info, tp, _, _) | Clang_ast_t.CXXConversionDecl (_, name_info, _, fdi, mdi)
| Clang_ast_t.CXXDestructorDecl (_, name_info, tp, _, _) -> | Clang_ast_t.CXXDestructorDecl (_, name_info, _, fdi, mdi) ->
let method_name = name_info.Clang_ast_t.ni_name in let method_name = name_info.Clang_ast_t.ni_name in
Printing.log_out " ...Declaring method '%s'.\n" method_name; 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 let mangled = General_utils.get_mangled_method_name fdi mdi in
Some method_proc let procname = General_utils.mk_procname_from_cpp_method class_name method_name mangled in
Some procname
| _ -> None in | _ -> None in
(* poor mans list_filter_map *) (* poor mans list_filter_map *)
IList.flatten_options (IList.map process_method_decl decl_list) IList.flatten_options (IList.map process_method_decl decl_list)

Loading…
Cancel
Save