diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index cb75874bd..92fab6751 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -302,86 +302,147 @@ struct let root_node' = GotoLabel.find_goto_label trans_state.context label_name sil_loc in { empty_res_trans with root_nodes = [root_node']; leaf_nodes = trans_state.succ_nodes } - let declRefExpr_trans trans_state stmt_info expr_info decl_ref_expr_info d = + let enum_constant_trans trans_state decl_ref = + let open CContext in + let context = trans_state.context in + let name_info, _ , type_ptr = get_info_from_decl_ref decl_ref in + let name = name_info.Clang_ast_t.ni_name in + let typ = CTypes_decl.type_ptr_to_sil_type context.tenv type_ptr in + let const_exp = match CTypes.search_enum_type_by_name context.tenv name with + | Some v -> + let ce = Sil.Const v in + Printing.log_out " ....Found enum constant '%s', " name; + Printing.log_out "replacing with integer '%s' \n" (Sil.exp_to_string ce); ce + | None -> + Printing.log_out + "WARNING: Found enum constant '%s', but its value was not found in the tenv.\n" + name; + (Sil.Const(Sil.Cint Sil.Int.zero)) in + { root_nodes = []; leaf_nodes = []; ids = []; instrs = []; exps = [(const_exp, typ)]} + + let function_deref_trans trans_state decl_ref = + let open CContext in + let context = trans_state.context in + let name_info, decl_ptr, type_ptr = get_info_from_decl_ref decl_ref in + let name = name_info.Clang_ast_t.ni_name in + let typ = CTypes_decl.type_ptr_to_sil_type context.tenv type_ptr in + 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 + 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.*) + (* As e.g. in fun_ptr = foo; *) + let non_mangled_func_name = + if name = CFrontend_config.malloc && + (!CFrontend_config.language = CFrontend_config.OBJC || + !CFrontend_config.language = CFrontend_config.OBJCPP) then + SymExec.ModelBuiltins.malloc_no_fail + else Procname.from_string_c_fun name in + let is_builtin = SymExec.function_is_builtin non_mangled_func_name in + if is_builtin then (* malloc, free, exit, scanf, ... *) + { empty_res_trans with exps = [(Sil.Const (Sil.Cfun non_mangled_func_name), typ)] } + else + begin + if address_of_function then Cfg.set_procname_priority context.cfg pname; + { empty_res_trans with exps = [(Sil.Const (Sil.Cfun pname), typ)] } + end + + let var_deref_trans trans_state stmt_info decl_ref = let open CContext in - Printing.log_out " priority node free = '%s'\n@." - (string_of_bool (PriorityNode.is_priority_free trans_state)); let context = trans_state.context in + let _, _, type_ptr = get_info_from_decl_ref decl_ref in + let typ = CTypes_decl.type_ptr_to_sil_type context.tenv type_ptr in + let procname = Cfg.Procdesc.get_proc_name context.procdesc in let pln = trans_state.parent_line_number in let sil_loc = CLocation.get_sil_location stmt_info pln context in - let tp = get_type_decl_ref_exp_info decl_ref_expr_info in - let typ = CTypes_decl.type_ptr_to_sil_type context.tenv tp in - let name = get_name_decl_ref_exp_info decl_ref_expr_info stmt_info in - let procname = Cfg.Procdesc.get_proc_name context.procdesc in - let pointer = CTrans_utils.get_decl_pointer decl_ref_expr_info in - let decl_kind = get_decl_kind decl_ref_expr_info in - match decl_kind with - | `EnumConstant -> - let const_exp = (match CTypes.search_enum_type_by_name context.tenv name with - | Some v -> - let ce = Sil.Const v in - Printing.log_out " ....Found enum constant '%s', " name; - Printing.log_out "replacing with integer '%s' \n" (Sil.exp_to_string ce); ce - | None -> - Printing.log_out - "WARNING: Found enum constant '%s', but its value was not found in the tenv.\n" - name; - (Sil.Const(Sil.Cint Sil.Int.zero))) in - { root_nodes = []; leaf_nodes = []; ids = []; instrs = []; exps = [(const_exp, typ)]} - | `Function -> - 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 pointer None name tp 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.*) - (* As e.g. in fun_ptr = foo; *) - let non_mangled_func_name = - if name = CFrontend_config.malloc && - (!CFrontend_config.language = CFrontend_config.OBJC || - !CFrontend_config.language = CFrontend_config.OBJCPP) then - SymExec.ModelBuiltins.malloc_no_fail - else Procname.from_string_c_fun name in - let is_builtin = SymExec.function_is_builtin non_mangled_func_name in - if is_builtin then (* malloc, free, exit, scanf, ... *) - { empty_res_trans with exps = [(Sil.Const (Sil.Cfun non_mangled_func_name), typ)] } + let pvar = CVar_decl.sil_var_of_decl_ref context decl_ref procname in + let e = Sil.Lvar pvar in + let exps = if Self.is_var_self pvar (CContext.is_objc_method context) then + let curr_class = CContext.get_curr_class context in + if (CTypes.is_class typ) then + raise (Self.SelfClassException (CContext.get_curr_class_name curr_class)) else - begin - if address_of_function then Cfg.set_procname_priority context.cfg pname; - { empty_res_trans with exps = [(Sil.Const (Sil.Cfun pname), typ)] } - end - | `Var | `ImplicitParam | `ParmVar -> - let pvar = - match decl_ref_expr_info.Clang_ast_t.drti_decl_ref with - | Some decl_ref -> CVar_decl.sil_var_of_decl_ref context decl_ref procname - | None -> assert false in - let e = Sil.Lvar pvar in - let exps = - if Self.is_var_self pvar (CContext.is_objc_method context) then - let curr_class = CContext.get_curr_class context in - if (CTypes.is_class typ) then - raise (Self.SelfClassException (CContext.get_curr_class_name curr_class)) - else - let typ = CTypes.add_pointer_to_typ - (CTypes_decl.get_type_curr_class context.tenv curr_class) in - [(e, typ)] - else [(e, typ)] in - Printing.log_out "\n\n PVAR ='%s'\n\n" (Sil.pvar_to_string pvar); - let res_trans = { empty_res_trans with exps = exps } in - if CTypes.is_reference_type tp then - (* dereference pvar due to the behavior of reference types in clang's AST *) - dereference_value_from_result sil_loc res_trans - else res_trans + let typ = CTypes.add_pointer_to_typ + (CTypes_decl.get_type_curr_class context.tenv curr_class) in + [(e, typ)] + else [(e, typ)] in + Printing.log_out "\n\n PVAR ='%s'\n\n" (Sil.pvar_to_string pvar); + let res_trans = { empty_res_trans with exps = exps } in + if CTypes.is_reference_type type_ptr then + (* dereference pvar due to the behavior of reference types in clang's AST *) + dereference_value_from_result sil_loc res_trans + else res_trans + + let field_deref_trans trans_state pre_trans_result decl_ref = + let open CContext in + let context = trans_state.context in + let name_info, _, type_ptr = get_info_from_decl_ref decl_ref in + Printing.log_out "!!!!! Dealing with field '%s' @." name_info.Clang_ast_t.ni_name; + let field_typ = CTypes_decl.type_ptr_to_sil_type context.tenv type_ptr in + let (obj_sil, class_typ) = extract_exp_from_list pre_trans_result.exps + "WARNING: in Field dereference we expect to know the object\n" in + let class_typ = + match class_typ with + | Sil.Tptr (t, _) -> CTypes.expand_structured_type context.CContext.tenv t + | t -> t in + Printing.log_out "Type is '%s' @." (Sil.typ_to_string class_typ); + let field_name = General_utils.mk_class_field_name name_info in + let exp = Sil.Lfield (obj_sil, field_name, class_typ) in + { pre_trans_result with exps = [(exp, field_typ)] } + + let method_deref_trans trans_state pre_trans_result decl_ref = + let open CContext in + let context = trans_state.context in + let name_info, decl_ptr, type_ptr = get_info_from_decl_ref decl_ref in + let method_name = name_info.Clang_ast_t.ni_name in + Printing.log_out "!!!!! Dealing with method '%s' @." method_name; + let method_typ = CTypes_decl.type_ptr_to_sil_type context.tenv type_ptr in + (* we don't handle C++ static methods yet - when they are called, this might cause a crash *) + assert (IList.length pre_trans_result.exps = 1); + let (obj_sil, class_typ) = extract_exp_from_list pre_trans_result.exps + "WARNING: in Method call we expect to know the object\n" in + let class_typ = + match class_typ with + | Sil.Tptr (t, _) -> CTypes.expand_structured_type context.CContext.tenv t + | t -> t in + (* consider using context.CContext.is_callee_expression to deal with pointers to methods? *) + let class_name = CTypes.classname_of_type class_typ in + let pname = CMethod_trans.create_procdesc_with_pointer context decl_ptr (Some class_name) + method_name type_ptr in + let method_exp = (Sil.Const (Sil.Cfun pname), method_typ) in + Cfg.set_procname_priority context.CContext.cfg pname; + (* TODO for static methods we shouldn't return (obj_sil, class_typ) *) + { pre_trans_result with exps = [method_exp; (obj_sil, class_typ)] } + + let decl_ref_trans trans_state pre_trans_result stmt_info expr_info decl_ref = + let open CContext in + Printing.log_out " priority node free = '%s'\n@." + (string_of_bool (PriorityNode.is_priority_free trans_state)); + let decl_kind = decl_ref.Clang_ast_t.dr_kind in + match decl_kind with + | `EnumConstant -> enum_constant_trans trans_state decl_ref + | `Function -> function_deref_trans trans_state decl_ref + | `Var | `ImplicitParam | `ParmVar -> var_deref_trans trans_state stmt_info decl_ref + | `Field | `ObjCIvar -> field_deref_trans trans_state pre_trans_result decl_ref + | `CXXMethod -> method_deref_trans trans_state pre_trans_result decl_ref | _ -> let print_error decl_kind = Printing.log_stats "Warning: Decl ref expression %s with pointer %s still needs to be translated " (Clang_ast_j.string_of_decl_kind decl_kind) - pointer in - match decl_kind with - | `CXXMethod -> print_error decl_kind; assert false - | _ -> print_error decl_kind; assert false + decl_ref.Clang_ast_t.dr_decl_pointer in + print_error decl_kind; assert false + + let declRefExpr_trans trans_state stmt_info expr_info decl_ref_expr_info e = + let open CContext in + Printing.log_out " priority node free = '%s'\n@." + (string_of_bool (PriorityNode.is_priority_free trans_state)); + let decl_ref = match decl_ref_expr_info.Clang_ast_t.drti_decl_ref with + | Some dr -> dr + | None -> assert false in + decl_ref_trans trans_state empty_res_trans stmt_info expr_info decl_ref let cxxThisExpr_trans trans_state stmt_info expr_info = let context = trans_state.context in @@ -1569,40 +1630,10 @@ struct (* function used in the computation for both Member_Expr and ObjCIVarRefExpr *) and do_memb_ivar_ref_exp trans_state expr_info stmt_info stmt_list decl_ref = - let context = trans_state.context in - let field_name = match decl_ref.Clang_ast_t.dr_name with - | Some s -> s - | _ -> assert false in - let field_tp = match decl_ref.Clang_ast_t.dr_type_ptr with - | Some t -> t - | _ -> assert false in - let field_typ = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv field_tp in - Printing.log_out "!!!!! Dealing with field '%s' @." field_name.Clang_ast_t.ni_name; let exp_stmt = extract_stmt_from_singleton stmt_list "WARNING: in MemberExpr there must be only one stmt defining its expression.\n" in let result_trans_exp_stmt = instruction trans_state exp_stmt in - let (obj_sil, class_typ) = extract_exp_from_list result_trans_exp_stmt.exps - "WARNING: in MemberExpr we expect the translation of the stmt to return an expression\n" in - let class_typ = - (match class_typ with - | Sil.Tptr (t, _) -> CTypes.expand_structured_type context.CContext.tenv t - | t -> t) in - match decl_ref.Clang_ast_t.dr_kind with - | `Field | `ObjCIvar -> - Printing.log_out "Type is '%s' @." (Sil.typ_to_string class_typ); - let fn = General_utils.mk_class_field_name field_name in - let exp = Sil.Lfield (obj_sil, fn, class_typ) in - { result_trans_exp_stmt with exps = [(exp, field_typ)] } - | `CXXMethod -> - (* consider using context.CContext.is_callee_expression to deal with pointers to methods? *) - let class_name = match class_typ with Sil.Tptr (t, _) | t -> CTypes.classname_of_type t in - let pointer = decl_ref.Clang_ast_t.dr_decl_pointer in - let pname = CMethod_trans.create_procdesc_with_pointer context pointer (Some class_name) - field_name.Clang_ast_t.ni_name field_tp in - let method_exp = (Sil.Const (Sil.Cfun pname), field_typ) in - Cfg.set_procname_priority context.CContext.cfg pname; - { result_trans_exp_stmt with exps = [method_exp; (obj_sil, class_typ)] } - | _ -> assert false + decl_ref_trans trans_state result_trans_exp_stmt stmt_info expr_info decl_ref and objCIvarRefExpr_trans trans_state stmt_info expr_info stmt_list obj_c_ivar_ref_expr_info = let decl_ref = obj_c_ivar_ref_expr_info.Clang_ast_t.ovrei_decl_ref in diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index 845df5022..83790e28a 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -461,50 +461,11 @@ let fix_param_exps_mismatch params_stmt exps_param = let exps'= exps_param @ (Array.to_list args) in exps' -let get_name_decl_ref_exp_info decl_ref_expr_info si = - match decl_ref_expr_info.Clang_ast_t.drti_decl_ref with - | Some d -> (match d.Clang_ast_t.dr_name with - | Some n -> n.Clang_ast_t.ni_name - | _ -> assert false) - | _ -> L.err "FAILING WITH %s pointer=%s@.@." - (Clang_ast_j.string_of_decl_ref_expr_info decl_ref_expr_info ) - (Clang_ast_j.string_of_stmt_info si); assert false - -let get_type_decl_ref_exp_info decl_ref_expr_info = - match decl_ref_expr_info.Clang_ast_t.drti_decl_ref with - | Some d -> (match d.Clang_ast_t.dr_type_ptr with - | Some ptr -> ptr - | _ -> assert false) - | _ -> assert false - let is_superinstance mei = match mei.Clang_ast_t.omei_receiver_kind with | `SuperInstance -> true | _ -> false -let get_name_decl_ref_exp stmt = - match stmt with - | `DeclRefExpr(si, _, _, drei) -> - get_name_decl_ref_exp_info drei si - | _ -> assert false - -(* given the type of the enumeration and an enumeration constant (defined *) -(* by stmt), returns the associated value *) -let get_value_enum_constant tenv enum_type stmt = - let constant = get_name_decl_ref_exp stmt in - let typename = Sil.TN_enum(Mangled.from_string enum_type) in - match Sil.tenv_lookup tenv typename with - | Some (Sil.Tenum enum_constants) -> - Printing.log_out ">>>Found enum with typename TN_typename('%s')\n" (Sil.typename_to_string typename); - let _, v = try - IList.find (fun (c, _) -> Mangled.equal c (Mangled.from_string constant)) enum_constants - with _ -> (Printing.log_err - "Enumeration constant '%s' not found. Cannot continue...\n" constant; assert false) in - v - | _ -> Printing.log_err - "Enum type '%s' not found in tenv. Cannot continue...\n" (Sil.typename_to_string typename); - assert false - let get_selector_receiver obj_c_message_expr_info = obj_c_message_expr_info.Clang_ast_t.omei_selector, obj_c_message_expr_info.Clang_ast_t.omei_receiver_kind @@ -594,16 +555,6 @@ struct end -let get_decl_kind decl_ref_expr_info = - match decl_ref_expr_info.Clang_ast_t.drti_decl_ref with - | Some decl_ref -> decl_ref.Clang_ast_t.dr_kind - | None -> assert false - -let get_decl_pointer decl_ref_expr_info = - match decl_ref_expr_info.Clang_ast_t.drti_decl_ref with - | Some decl_ref -> decl_ref.Clang_ast_t.dr_decl_pointer - | None -> assert false - (* From the manual: A selector is in a certain selector family if, ignoring any leading underscores, *) (* the first component of the selector either consists entirely of the name of *) (* the method family or it begins with that followed by character other than lower case letter.*) @@ -645,6 +596,12 @@ let rec is_method_call s = | [] -> false | s'':: _ -> is_method_call s'') +let get_info_from_decl_ref decl_ref = + let name_info = match decl_ref.Clang_ast_t.dr_name with Some ni -> ni | _ -> assert false in + let decl_ptr = decl_ref.Clang_ast_t.dr_decl_pointer in + let type_ptr = match decl_ref.Clang_ast_t.dr_type_ptr with Some tp -> tp | _ -> assert false in + name_info, decl_ptr, type_ptr + let rec get_decl_ref_info s parent_line_number = match s with | Clang_ast_t.DeclRefExpr (stmt_info, stmt_list, expr_info, decl_ref_expr_info) -> @@ -695,6 +652,11 @@ let is_dispatch_function stmt_list = | _ -> None)) | _ -> None +let get_decl_pointer decl_ref_expr_info = + match decl_ref_expr_info.Clang_ast_t.drti_decl_ref with + | Some decl_ref -> decl_ref.Clang_ast_t.dr_decl_pointer + | None -> assert false + let rec pointer_of_call_expr stmt = let open Clang_ast_t in match stmt with diff --git a/infer/src/clang/cTrans_utils.mli b/infer/src/clang/cTrans_utils.mli index 56f14659b..b70392ade 100644 --- a/infer/src/clang/cTrans_utils.mli +++ b/infer/src/clang/cTrans_utils.mli @@ -69,14 +69,6 @@ val compute_instr_ids_exp_to_parent : Sil.exp -> Sil.typ -> Location.t -> priority_node -> Sil.instr list * Ident.t list * (Sil.exp * Sil.typ) list -val get_name_decl_ref_exp_info : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.stmt_info -> string - -val get_type_decl_ref_exp_info : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.type_ptr - -val get_decl_kind : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.decl_kind - -val get_decl_pointer : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.pointer - val is_enumeration_constant : Clang_ast_t.stmt -> bool val is_member_exp : Clang_ast_t.stmt -> bool @@ -103,6 +95,9 @@ val is_method_call : Clang_ast_t.stmt -> bool val contains_opaque_value_expr : Clang_ast_t.stmt -> bool +val get_info_from_decl_ref : Clang_ast_t.decl_ref -> + Clang_ast_t.named_decl_info * Clang_ast_t.pointer * Clang_ast_t.type_ptr + val get_decl_ref_info : Clang_ast_t.stmt -> int -> Clang_ast_t.decl_ref * int val builtin_trans : trans_state -> Location.t -> Clang_ast_t.stmt_info ->