Skip Sil.Call instruction for some shared_ptr method calls

Summary:
1. Add capability to clang frontend to replace some function calls with another SIL code based on `__deprecated__` attribute.
2. Given this capability, use those attributes for shared_ptr getters to generate `Sil.Load` instruction instead of method call
3. Add test that mimics shared_ptr model, but it doesn't have that much scary C++ templated code

Reviewed By: jvillard, jberdine

Differential Revision: D3729176

fbshipit-source-id: 2a330d5
master
Andrzej Kotulski 9 years ago committed by Facebook Github Bot 8
parent 2baf3f8456
commit 4cd9470586

@ -240,13 +240,17 @@ class shared_ptr : public std__shared_ptr<T> {
}
// observers:
T* get() const noexcept { return model_get(__cast_to_infer_ptr(this)); }
typename add_lvalue_reference<T>::type operator*() const noexcept {
return *model_get(__cast_to_infer_ptr(this));
T* get() const noexcept __attribute__((deprecated(
"__infer_replace_with_deref_first_arg"))) { /* return
model_get(__cast_to_infer_ptr(this)); */
}
typename std::add_lvalue_reference<T>::type operator*() const noexcept
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {
/*return *model_get(__cast_to_infer_ptr(this));*/
}
T* operator->() const noexcept {
return model_get(__cast_to_infer_ptr(this));
T* operator->() const noexcept
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {
/*return model_get(__cast_to_infer_ptr(this));*/
}
long use_count() const noexcept { return 2; /* FIXME */ }
bool unique() const noexcept { return use_count() == 1; /* FIXME */ }

@ -73,7 +73,8 @@ let static = "static"
let string_with_utf8_m = "stringWithUTF8String:"
let this = "this"
let void = "void"
let replace_with_deref_first_arg_attr = "__infer_replace_with_deref_first_arg"
let modeled_function_attributes = [replace_with_deref_first_arg_attr]
(** Global state *)

@ -73,7 +73,8 @@ val static : string
val string_with_utf8_m : string
val this : string
val void : string
val replace_with_deref_first_arg_attr : string
val modeled_function_attributes : string list
(** Global state *)
@ -93,4 +94,3 @@ val pointer_type_index : Clang_ast_t.c_type Clang_ast_main.PointerMap.t ref
(** Map from type pointers (clang pointers and types created later by frontend) to sil types
Populated during frontend execution when new type is found *)
val sil_types_map : (Typ.t Clang_ast_types.TypePointerMap.t) ref

@ -441,6 +441,29 @@ 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 get_builtin_pname_opt name decl_opt =
let get_deprecated_attr_arg decl =
let open Clang_ast_t in
let decl_info = Clang_ast_proj.get_decl_tuple decl in
let get_attr_opt = function DeprecatedAttr a -> Some a | _ -> None in
match IList.find_map_opt get_attr_opt decl_info.di_attributes with
| Some attribute_info ->
(match attribute_info.ai_parameters with
| [_; arg; _] -> Some arg
| _ ->
(* it's not supposed to happen due to hardcoded exporting logic
coming from ASTExporter.h in facebook-clang-plugins *)
assert false)
| None -> None in
let function_attr_opt = Option.map_default get_deprecated_attr_arg None decl_opt in
match function_attr_opt with
| Some attr when CTrans_models.is_modeled_attribute attr ->
Some (Procname.from_string_c_fun attr)
| _ when CTrans_models.is_modeled_builtin name ->
Some (Procname.from_string_c_fun (CFrontend_config.infer ^ name))
| _ -> None
let function_deref_trans trans_state decl_ref =
let open CContext in
let context = trans_state.context in
@ -449,10 +472,9 @@ struct
Option.may (call_translation context) decl_opt;
let name = Ast_utils.get_qualified_name name_info 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 in
let pname = match get_builtin_pname_opt name decl_opt with
| Some builtin_pname -> builtin_pname
| None -> 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.*)
@ -551,10 +573,17 @@ struct
[], [] in
(* 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 *)
(* use qualified method name for builtin matching, but use unqualified name elsewhere *)
let qual_method_name = Ast_utils.get_qualified_name name_info in
let pname = match get_builtin_pname_opt qual_method_name decl_opt with
| Some builtin_pname -> builtin_pname
| None ->
let pname = CMethod_trans.create_procdesc_with_pointer context decl_ptr (Some class_name)
method_name in
let method_exp = (Exp.Const (Const.Cfun pname), method_typ) in
Cfg.set_procname_priority context.CContext.cfg pname;
pname in
let method_exp = (Exp.Const (Const.Cfun pname), method_typ) in
{ pre_trans_result with
is_cpp_call_virtual = is_cpp_virtual;
exps = [method_exp] @ extra_exps;
@ -925,7 +954,7 @@ struct
result_trans_callee :: res_trans_p in
(* first expr is method address, rest are params including 'this' parameter *)
let actual_params = IList.tl (collect_exprs result_trans_subexprs) in
match cxx_method_builtin_trans trans_state_pri sil_loc callee_pname with
match cxx_method_builtin_trans trans_state_pri sil_loc result_trans_subexprs callee_pname with
| Some builtin -> builtin
| _ ->
let call_flags = {

@ -31,7 +31,10 @@ let is_builtin_expect pname =
Procname.to_string pname = CFrontend_config.builtin_expect
let is_builtin_object_size pname =
(Procname.to_string pname) == CFrontend_config.builtin_object_size
(Procname.to_string pname) = CFrontend_config.builtin_object_size
let is_replace_with_deref_first_arg pname =
(Procname.to_string pname) = CFrontend_config.replace_with_deref_first_arg_attr
let rec get_func_type_from_stmt stmt =
match stmt with
@ -72,6 +75,9 @@ let get_builtinname method_name =
let is_modeled_builtin funct =
funct = CFrontend_config.builtin_memset_chk
let is_modeled_attribute attr_name =
IList.mem string_equal attr_name CFrontend_config.modeled_function_attributes
let is_assert_log_s funct =
funct = CFrontend_config.assert_rtn ||
funct = CFrontend_config.assert_fail ||

@ -19,6 +19,8 @@ val is_builtin_expect : Procname.t -> bool
val is_builtin_object_size : Procname.t -> bool
val is_replace_with_deref_first_arg : Procname.t -> bool
val is_objc_memory_model_controlled : string -> bool
val builtin_predefined_model : Clang_ast_t.stmt -> Procname.t option -> Procname.t option * bool
@ -29,6 +31,8 @@ val is_handleFailureInMethod : string -> bool
val is_modeled_builtin : string -> bool
val is_modeled_attribute : string -> bool
val is_toll_free_bridging : Procname.t -> bool
val get_predefined_model_method_signature : string -> string ->

@ -467,6 +467,17 @@ let trans_builtin_expect params_trans_res =
| [_; fst_arg_res; _] -> Some fst_arg_res
| _ -> None
let trans_replace_with_deref_first_arg sil_loc params_trans_res ~cxx_method_call =
let first_arg_res_trans = match params_trans_res with
| _ :: fst_arg_res :: _ when not cxx_method_call -> fst_arg_res
| ({exps= _method_exp :: this_exp} as fst_arg_res) :: _ when cxx_method_call ->
(* method_deref_trans uses different format to store first argument - it stores
two things in exps: [method_exp; this_exp].
We need to get rid of first exp before calling dereference_value_from_result *)
{ fst_arg_res with exps = this_exp }
| _ -> assert false in
dereference_value_from_result sil_loc first_arg_res_trans ~strip_pointer:true
let builtin_trans trans_state loc stmt_info function_type params_trans_res pname =
if CTrans_models.is_cf_non_null_alloc pname ||
CTrans_models.is_alloc_model function_type pname then
@ -477,11 +488,15 @@ let builtin_trans trans_state loc stmt_info function_type params_trans_res pname
Some (trans_assertion trans_state loc)
else if CTrans_models.is_builtin_expect pname then
trans_builtin_expect params_trans_res
else if CTrans_models.is_replace_with_deref_first_arg pname then
Some (trans_replace_with_deref_first_arg loc params_trans_res ~cxx_method_call:false)
else None
let cxx_method_builtin_trans trans_state loc pname =
let cxx_method_builtin_trans trans_state loc params_trans_res pname =
if CTrans_models.is_assert_log pname then
Some (trans_assertion trans_state loc)
else if CTrans_models.is_replace_with_deref_first_arg pname then
Some (trans_replace_with_deref_first_arg loc params_trans_res ~cxx_method_call:true)
else
None

@ -101,8 +101,8 @@ val get_decl_ref_info : Clang_ast_t.stmt -> Clang_ast_t.decl_ref
val builtin_trans : trans_state -> Location.t -> Clang_ast_t.stmt_info ->
Typ.t -> trans_result list -> Procname.t -> trans_result option
val cxx_method_builtin_trans : trans_state -> Location.t -> Procname.t ->
trans_result option
val cxx_method_builtin_trans : trans_state -> Location.t -> trans_result list ->
Procname.t -> trans_result option
val alloc_trans :
trans_state -> Location.t -> Clang_ast_t.stmt_info -> Typ.t -> bool ->

@ -0,0 +1,151 @@
/*
* Copyright (c) 2016 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
// header required by TranslateAsPtr class. It's not in common header search
// path when running clang without infer (clang wrappers add it)
// Add -isystem '/path/models/cpp/include' to clang invocation to work around
// compilation problem
#include <infer_model/infer_traits.h>
/* Test for passing function attributes to infer via __deprecated__ attribute */
// basic test of C function with __infer_replace_with_deref_first_arg attribute
int derefFirstArg(int* a, int* b)
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {
/* equivalent in real code:
return *a; */
}
int derefFirstArg2(int* a, int* b)
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {
/* equivalent in real code:
return *a; */
return *b; // body is in conflict with the attribute, attribute semantics
// should be used
}
int derefFirstArg3(int* a, int* b) __attribute__((deprecated("__infer_typo"))) {
/* equivalent in real code: */
return *b; // there isn't any known attribute with this name, use semantics
// from the body
}
int derefFirstArg_null_deref() {
int a = 0;
return derefFirstArg(nullptr, &a);
}
int derefFirstArg_ok_deref() {
int a = 0;
return derefFirstArg(&a, nullptr);
}
int derefFirstArg2_null_deref() {
int a = 0;
return derefFirstArg2(nullptr, &a);
}
int derefFirstArg2_ok_deref() {
int a = 0;
return derefFirstArg2(&a, nullptr);
}
int derefFirstArg3_ok_deref() {
int a = 0;
return derefFirstArg3(nullptr, &a);
}
int derefFirstArg3_null_deref() {
int a = 0;
return derefFirstArg3(&a, nullptr);
}
// more involving test of __infer_replace_with_deref_first_arg attribute in
// context of C++
// methods
/* This class be translated as T* by infer frontend - same as shared_ptr
This class has different API in order to better test __deprecated__ attribute
handling by the frontend. */
template <class T>
struct TranslateAsPtr {
friend class infer_traits::TranslateAsType<T*>;
TranslateAsPtr(T* t = nullptr) { setPtr(t); }
/* calls to those functions are supposed to be translated as `*this` */
T* getPtr()
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
T* getPtr(int a, int b)
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
/* calls to those functions are supposed to be translated as `**this` */
T& operator*()
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
T& getRef()
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
T& getRef(int a, int b)
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
// same trick we do for setting value of shared_ptr, look there for details
void setPtr(T* v) { *((void**)(this)) = v; }
};
int getPtr_null_deref1() {
TranslateAsPtr<int> t;
t.setPtr(nullptr);
return *t.getPtr();
}
int getPtr_null_deref2() {
TranslateAsPtr<int> t;
t.setPtr(nullptr);
return *t.getPtr(1, 2);
}
int getPtr_ok_deref() {
int a = 0;
TranslateAsPtr<int> t;
t.setPtr(&a);
return *t.getPtr();
}
int operator_star_null_deref1() {
TranslateAsPtr<int> t;
t.setPtr(nullptr);
return *t; // call operator* via operator call
}
int operator_star_null_deref2() {
TranslateAsPtr<int> t;
t.setPtr(nullptr);
return t.operator*(); // call operator* via regular method call
}
int operator_star_ok_deref() {
int a;
TranslateAsPtr<int> t;
t.setPtr(&a);
return t.operator*(); // call operator* via regular method call
}
int getRef_null_deref1() {
TranslateAsPtr<int> t;
t.setPtr(nullptr);
return t.getRef();
}
int getRef_null_deref2() {
TranslateAsPtr<int> t;
t.setPtr(nullptr);
return t.getRef(1, 2);
}
int getRef_ok_deref() {
int a = 0;
TranslateAsPtr<int> t;
t.setPtr(&a);
return t.getRef();
}

@ -0,0 +1,358 @@
/* @generated */
digraph iCFG {
95 [label="95: DeclStmt \n *&a:int =0 [line 147]\n " shape="box"]
95 -> 94 ;
94 [label="94: DeclStmt \n _fun_TranslateAsPtr<int>_TranslateAsPtr(&t:int **,null:int *) [line 148]\n n$4=*&t:int * [line 148]\n " shape="box"]
94 -> 93 ;
93 [label="93: Call _fun_TranslateAsPtr<int>_setPtr \n _=*&t:int * [line 149]\n _fun_TranslateAsPtr<int>_setPtr(&t:int *&,&a:int *) [line 149]\n " shape="box"]
93 -> 92 ;
92 [label="92: Return Stmt \n _=*&t:int * [line 150]\n n$1=*&t:int *& [line 150]\n n$2=*n$1:int * [line 150]\n *&return:int =n$2 [line 150]\n " shape="box"]
92 -> 91 ;
91 [label="91: Exit getRef_ok_deref \n " color=yellow style=filled]
90 [label="90: Start getRef_ok_deref\nFormals: \nLocals: t:int * a:int \n DECLARE_LOCALS(&return,&t,&a); [line 146]\n " color=yellow style=filled]
90 -> 95 ;
89 [label="89: DeclStmt \n _fun_TranslateAsPtr<int>_TranslateAsPtr(&t:int **,null:int *) [line 141]\n n$4=*&t:int * [line 141]\n " shape="box"]
89 -> 88 ;
88 [label="88: Call _fun_TranslateAsPtr<int>_setPtr \n _=*&t:int * [line 142]\n _fun_TranslateAsPtr<int>_setPtr(&t:int *&,null:int *) [line 142]\n " shape="box"]
88 -> 87 ;
87 [label="87: Return Stmt \n _=*&t:int * [line 143]\n n$1=*&t:int *& [line 143]\n n$2=*n$1:int * [line 143]\n *&return:int =n$2 [line 143]\n " shape="box"]
87 -> 86 ;
86 [label="86: Exit getRef_null_deref2 \n " color=yellow style=filled]
85 [label="85: Start getRef_null_deref2\nFormals: \nLocals: t:int * \n DECLARE_LOCALS(&return,&t); [line 140]\n " color=yellow style=filled]
85 -> 89 ;
84 [label="84: DeclStmt \n _fun_TranslateAsPtr<int>_TranslateAsPtr(&t:int **,null:int *) [line 135]\n n$4=*&t:int * [line 135]\n " shape="box"]
84 -> 83 ;
83 [label="83: Call _fun_TranslateAsPtr<int>_setPtr \n _=*&t:int * [line 136]\n _fun_TranslateAsPtr<int>_setPtr(&t:int *&,null:int *) [line 136]\n " shape="box"]
83 -> 82 ;
82 [label="82: Return Stmt \n _=*&t:int * [line 137]\n n$1=*&t:int *& [line 137]\n n$2=*n$1:int * [line 137]\n *&return:int =n$2 [line 137]\n " shape="box"]
82 -> 81 ;
81 [label="81: Exit getRef_null_deref1 \n " color=yellow style=filled]
80 [label="80: Start getRef_null_deref1\nFormals: \nLocals: t:int * \n DECLARE_LOCALS(&return,&t); [line 134]\n " color=yellow style=filled]
80 -> 84 ;
79 [label="79: DeclStmt \n _fun_TranslateAsPtr<int>_TranslateAsPtr(&t:int **,null:int *) [line 129]\n n$4=*&t:int * [line 129]\n " shape="box"]
79 -> 78 ;
78 [label="78: Call _fun_TranslateAsPtr<int>_setPtr \n _=*&t:int * [line 130]\n _fun_TranslateAsPtr<int>_setPtr(&t:int *&,&a:int *) [line 130]\n " shape="box"]
78 -> 77 ;
77 [label="77: Return Stmt \n _=*&t:int * [line 131]\n n$1=*&t:int *& [line 131]\n n$2=*n$1:int * [line 131]\n *&return:int =n$2 [line 131]\n " shape="box"]
77 -> 76 ;
76 [label="76: Exit operator_star_ok_deref \n " color=yellow style=filled]
75 [label="75: Start operator_star_ok_deref\nFormals: \nLocals: t:int * a:int \n DECLARE_LOCALS(&return,&t,&a); [line 127]\n " color=yellow style=filled]
75 -> 79 ;
74 [label="74: DeclStmt \n _fun_TranslateAsPtr<int>_TranslateAsPtr(&t:int **,null:int *) [line 122]\n n$4=*&t:int * [line 122]\n " shape="box"]
74 -> 73 ;
73 [label="73: Call _fun_TranslateAsPtr<int>_setPtr \n _=*&t:int * [line 123]\n _fun_TranslateAsPtr<int>_setPtr(&t:int *&,null:int *) [line 123]\n " shape="box"]
73 -> 72 ;
72 [label="72: Return Stmt \n _=*&t:int * [line 124]\n n$1=*&t:int *& [line 124]\n n$2=*n$1:int * [line 124]\n *&return:int =n$2 [line 124]\n " shape="box"]
72 -> 71 ;
71 [label="71: Exit operator_star_null_deref2 \n " color=yellow style=filled]
70 [label="70: Start operator_star_null_deref2\nFormals: \nLocals: t:int * \n DECLARE_LOCALS(&return,&t); [line 121]\n " color=yellow style=filled]
70 -> 74 ;
69 [label="69: DeclStmt \n _fun_TranslateAsPtr<int>_TranslateAsPtr(&t:int **,null:int *) [line 116]\n n$3=*&t:int * [line 116]\n " shape="box"]
69 -> 68 ;
68 [label="68: Call _fun_TranslateAsPtr<int>_setPtr \n _=*&t:int * [line 117]\n _fun_TranslateAsPtr<int>_setPtr(&t:int *&,null:int *) [line 117]\n " shape="box"]
68 -> 67 ;
67 [label="67: Return Stmt \n n$0=*&t:int *& [line 118]\n n$1=*n$0:int * [line 118]\n *&return:int =n$1 [line 118]\n " shape="box"]
67 -> 66 ;
66 [label="66: Exit operator_star_null_deref1 \n " color=yellow style=filled]
65 [label="65: Start operator_star_null_deref1\nFormals: \nLocals: t:int * \n DECLARE_LOCALS(&return,&t); [line 115]\n " color=yellow style=filled]
65 -> 69 ;
64 [label="64: DeclStmt \n *&a:int =0 [line 109]\n " shape="box"]
64 -> 63 ;
63 [label="63: DeclStmt \n _fun_TranslateAsPtr<int>_TranslateAsPtr(&t:int **,null:int *) [line 110]\n n$4=*&t:int * [line 110]\n " shape="box"]
63 -> 62 ;
62 [label="62: Call _fun_TranslateAsPtr<int>_setPtr \n _=*&t:int * [line 111]\n _fun_TranslateAsPtr<int>_setPtr(&t:int *&,&a:int *) [line 111]\n " shape="box"]
62 -> 61 ;
61 [label="61: Return Stmt \n _=*&t:int * [line 112]\n n$1=*&t:int *& [line 112]\n n$2=*n$1:int [line 112]\n *&return:int =n$2 [line 112]\n " shape="box"]
61 -> 60 ;
60 [label="60: Exit getPtr_ok_deref \n " color=yellow style=filled]
59 [label="59: Start getPtr_ok_deref\nFormals: \nLocals: t:int * a:int \n DECLARE_LOCALS(&return,&t,&a); [line 108]\n " color=yellow style=filled]
59 -> 64 ;
58 [label="58: DeclStmt \n _fun_TranslateAsPtr<int>_TranslateAsPtr(&t:int **,null:int *) [line 103]\n n$4=*&t:int * [line 103]\n " shape="box"]
58 -> 57 ;
57 [label="57: Call _fun_TranslateAsPtr<int>_setPtr \n _=*&t:int * [line 104]\n _fun_TranslateAsPtr<int>_setPtr(&t:int *&,null:int *) [line 104]\n " shape="box"]
57 -> 56 ;
56 [label="56: Return Stmt \n _=*&t:int * [line 105]\n n$1=*&t:int *& [line 105]\n n$2=*n$1:int [line 105]\n *&return:int =n$2 [line 105]\n " shape="box"]
56 -> 55 ;
55 [label="55: Exit getPtr_null_deref2 \n " color=yellow style=filled]
54 [label="54: Start getPtr_null_deref2\nFormals: \nLocals: t:int * \n DECLARE_LOCALS(&return,&t); [line 102]\n " color=yellow style=filled]
54 -> 58 ;
53 [label="53: DeclStmt \n _fun_TranslateAsPtr<int>_TranslateAsPtr(&t:int **,null:int *) [line 97]\n n$4=*&t:int * [line 97]\n " shape="box"]
53 -> 52 ;
52 [label="52: Call _fun_TranslateAsPtr<int>_setPtr \n _=*&t:int * [line 98]\n _fun_TranslateAsPtr<int>_setPtr(&t:int *&,null:int *) [line 98]\n " shape="box"]
52 -> 51 ;
51 [label="51: Return Stmt \n _=*&t:int * [line 99]\n n$1=*&t:int *& [line 99]\n n$2=*n$1:int [line 99]\n *&return:int =n$2 [line 99]\n " shape="box"]
51 -> 50 ;
50 [label="50: Exit getPtr_null_deref1 \n " color=yellow style=filled]
49 [label="49: Start getPtr_null_deref1\nFormals: \nLocals: t:int * \n DECLARE_LOCALS(&return,&t); [line 96]\n " color=yellow style=filled]
49 -> 53 ;
48 [label="48: Exit TranslateAsPtr<int>_getRef \n " color=yellow style=filled]
47 [label="47: Start TranslateAsPtr<int>_getRef\nFormals: this:int ** a:int b:int \nLocals: \n DECLARE_LOCALS(&return); [line 89]\n " color=yellow style=filled]
47 -> 48 ;
46 [label="46: Exit TranslateAsPtr<int>_getRef \n " color=yellow style=filled]
45 [label="45: Start TranslateAsPtr<int>_getRef\nFormals: this:int **\nLocals: \n DECLARE_LOCALS(&return); [line 87]\n " color=yellow style=filled]
45 -> 46 ;
44 [label="44: Exit TranslateAsPtr<int>_operator* \n " color=yellow style=filled]
43 [label="43: Start TranslateAsPtr<int>_operator*\nFormals: this:int **\nLocals: \n DECLARE_LOCALS(&return); [line 85]\n " color=yellow style=filled]
43 -> 44 ;
42 [label="42: Exit TranslateAsPtr<int>_getPtr \n " color=yellow style=filled]
41 [label="41: Start TranslateAsPtr<int>_getPtr\nFormals: this:int ** a:int b:int \nLocals: \n DECLARE_LOCALS(&return); [line 82]\n " color=yellow style=filled]
41 -> 42 ;
40 [label="40: Exit TranslateAsPtr<int>_getPtr \n " color=yellow style=filled]
39 [label="39: Start TranslateAsPtr<int>_getPtr\nFormals: this:int **\nLocals: \n DECLARE_LOCALS(&return); [line 80]\n " color=yellow style=filled]
39 -> 40 ;
38 [label="38: Call _fun_TranslateAsPtr<int>_setPtr \n n$0=*&this:int ** [line 78]\n _=*n$0:int * [line 78]\n n$2=*&t:int * [line 78]\n _fun_TranslateAsPtr<int>_setPtr(n$0:int **,n$2:int *) [line 78]\n " shape="box"]
38 -> 34 ;
37 [label="37: BinaryOperatorStmt: Assign \n n$0=*&this:int ** [line 93]\n n$1=*&v:int * [line 93]\n *n$0:void *=n$1 [line 93]\n " shape="box"]
37 -> 36 ;
36 [label="36: Exit TranslateAsPtr<int>_setPtr \n " color=yellow style=filled]
35 [label="35: Start TranslateAsPtr<int>_setPtr\nFormals: this:int ** v:int *\nLocals: \n DECLARE_LOCALS(&return); [line 93]\n " color=yellow style=filled]
35 -> 37 ;
34 [label="34: Exit TranslateAsPtr<int>_TranslateAsPtr \n " color=yellow style=filled]
33 [label="33: Start TranslateAsPtr<int>_TranslateAsPtr\nFormals: this:int ** t:int *\nLocals: \n DECLARE_LOCALS(&return); [line 78]\n " color=yellow style=filled]
33 -> 38 ;
32 [label="32: DeclStmt \n *&a:int =0 [line 65]\n " shape="box"]
32 -> 31 ;
31 [label="31: Return Stmt \n n$0=_fun_derefFirstArg3(&a:int *,null:int *) [line 66]\n *&return:int =n$0 [line 66]\n " shape="box"]
31 -> 30 ;
30 [label="30: Exit derefFirstArg3_null_deref \n " color=yellow style=filled]
29 [label="29: Start derefFirstArg3_null_deref\nFormals: \nLocals: a:int \n DECLARE_LOCALS(&return,&a); [line 64]\n " color=yellow style=filled]
29 -> 32 ;
28 [label="28: DeclStmt \n *&a:int =0 [line 60]\n " shape="box"]
28 -> 27 ;
27 [label="27: Return Stmt \n n$0=_fun_derefFirstArg3(null:int *,&a:int *) [line 61]\n *&return:int =n$0 [line 61]\n " shape="box"]
27 -> 26 ;
26 [label="26: Exit derefFirstArg3_ok_deref \n " color=yellow style=filled]
25 [label="25: Start derefFirstArg3_ok_deref\nFormals: \nLocals: a:int \n DECLARE_LOCALS(&return,&a); [line 59]\n " color=yellow style=filled]
25 -> 28 ;
24 [label="24: DeclStmt \n *&a:int =0 [line 55]\n " shape="box"]
24 -> 23 ;
23 [label="23: Return Stmt \n n$0=*&a:int * [line 56]\n *&return:int =n$0 [line 56]\n " shape="box"]
23 -> 22 ;
22 [label="22: Exit derefFirstArg2_ok_deref \n " color=yellow style=filled]
21 [label="21: Start derefFirstArg2_ok_deref\nFormals: \nLocals: a:int \n DECLARE_LOCALS(&return,&a); [line 54]\n " color=yellow style=filled]
21 -> 24 ;
20 [label="20: DeclStmt \n *&a:int =0 [line 50]\n " shape="box"]
20 -> 19 ;
19 [label="19: Return Stmt \n n$0=*null:int * [line 51]\n *&return:int =n$0 [line 51]\n " shape="box"]
19 -> 18 ;
18 [label="18: Exit derefFirstArg2_null_deref \n " color=yellow style=filled]
17 [label="17: Start derefFirstArg2_null_deref\nFormals: \nLocals: a:int \n DECLARE_LOCALS(&return,&a); [line 49]\n " color=yellow style=filled]
17 -> 20 ;
16 [label="16: DeclStmt \n *&a:int =0 [line 45]\n " shape="box"]
16 -> 15 ;
15 [label="15: Return Stmt \n n$0=*&a:int * [line 46]\n *&return:int =n$0 [line 46]\n " shape="box"]
15 -> 14 ;
14 [label="14: Exit derefFirstArg_ok_deref \n " color=yellow style=filled]
13 [label="13: Start derefFirstArg_ok_deref\nFormals: \nLocals: a:int \n DECLARE_LOCALS(&return,&a); [line 44]\n " color=yellow style=filled]
13 -> 16 ;
12 [label="12: DeclStmt \n *&a:int =0 [line 40]\n " shape="box"]
12 -> 11 ;
11 [label="11: Return Stmt \n n$0=*null:int * [line 41]\n *&return:int =n$0 [line 41]\n " shape="box"]
11 -> 10 ;
10 [label="10: Exit derefFirstArg_null_deref \n " color=yellow style=filled]
9 [label="9: Start derefFirstArg_null_deref\nFormals: \nLocals: a:int \n DECLARE_LOCALS(&return,&a); [line 39]\n " color=yellow style=filled]
9 -> 12 ;
8 [label="8: Return Stmt \n n$0=*&b:int * [line 35]\n n$1=*n$0:int [line 35]\n *&return:int =n$1 [line 35]\n " shape="box"]
8 -> 7 ;
7 [label="7: Exit derefFirstArg3 \n " color=yellow style=filled]
6 [label="6: Start derefFirstArg3\nFormals: a:int * b:int *\nLocals: \n DECLARE_LOCALS(&return); [line 33]\n " color=yellow style=filled]
6 -> 8 ;
5 [label="5: Return Stmt \n n$0=*&b:int * [line 29]\n n$1=*n$0:int [line 29]\n *&return:int =n$1 [line 29]\n " shape="box"]
5 -> 4 ;
4 [label="4: Exit derefFirstArg2 \n " color=yellow style=filled]
3 [label="3: Start derefFirstArg2\nFormals: a:int * b:int *\nLocals: \n DECLARE_LOCALS(&return); [line 25]\n " color=yellow style=filled]
3 -> 5 ;
2 [label="2: Exit derefFirstArg \n " color=yellow style=filled]
1 [label="1: Start derefFirstArg\nFormals: a:int * b:int *\nLocals: \n DECLARE_LOCALS(&return); [line 19]\n " color=yellow style=filled]
1 -> 2 ;
}

@ -0,0 +1,72 @@
/*
* Copyright (c) 2016 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package endtoend.cpp.infer;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsExactly.containsExactly;
import com.google.common.collect.ImmutableList;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import java.io.IOException;
import utils.DebuggableTemporaryFolder;
import utils.InferException;
import utils.InferResults;
import utils.InferRunner;
public class DeprecatedHackTest {
public static final String SOURCE_FILE =
"infer/tests/codetoanalyze/cpp/frontend/attributes/deprecated_hack.cpp";
public static final String NULL_DEREFERENCE = "NULL_DEREFERENCE";
private static ImmutableList<String> inferCmd;
@ClassRule
public static DebuggableTemporaryFolder folder =
new DebuggableTemporaryFolder();
@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferCmd = InferRunner.createCPPInferCommand(folder, SOURCE_FILE);
}
@Test
public void whenInferRunsOnNullDerefThenNullDereferenceIsFound()
throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferC(inferCmd);
String[] procedures = {
"derefFirstArg_null_deref",
"derefFirstArg2_null_deref",
"derefFirstArg3_null_deref",
"getPtr_null_deref1",
"getPtr_null_deref2",
"operator_star_null_deref1",
"operator_star_null_deref2",
"getRef_null_deref1",
"getRef_null_deref2",
};
assertThat(
"Results should contain divide by zero error",
inferResults,
containsExactly(
NULL_DEREFERENCE,
SOURCE_FILE,
procedures
)
);
}
}

@ -35,4 +35,9 @@ public class AttributesTest {
frontendTest("clang_fallthrough.cpp");
}
@Test
public void testDeprecatedHackDotFilesMatch()
throws InterruptedException, IOException, InferException {
frontendTest("deprecated_hack.cpp");
}
}

Loading…
Cancel
Save