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
#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

@ -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

@ -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

@ -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

@ -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 *)

@ -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

@ -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

@ -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)

Loading…
Cancel
Save