Translate c++ constructor calls in var initialization

Summary: public
Translate CXXConstructExpr that are parts of variable initialization.

Reviewed By: dulmarod

Differential Revision: D2570750

fb-gh-sync-id: 708a457
master
Andrzej Kotulski 9 years ago committed by facebook-github-bot-1
parent ae49cacee8
commit a9bdf2b291

@ -423,7 +423,7 @@ struct
| `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
| `CXXMethod | `CXXConstructor -> method_deref_trans trans_state pre_trans_result decl_ref
| _ ->
let print_error decl_kind =
Printing.log_stats
@ -712,12 +712,11 @@ struct
| _ -> assert false) (* by construction of red_id, we cannot be in this case *)
and cxx_method_construct_call_trans trans_state_pri result_trans_callee fun_stmt params_stmt
si expr_info =
si function_type =
let open CContext in
let pln = trans_state_pri.parent_line_number in
let line_number = CLocation.get_line si pln in
let context = trans_state_pri.context in
let function_type = CTypes_decl.get_type_from_expr_info expr_info context.tenv in
let procname = Cfg.Procdesc.get_proc_name context.procdesc in
let sil_loc = CLocation.get_sil_location si pln context in
(* first for method address, second for 'this' expression *)
@ -762,6 +761,7 @@ struct
and cxxMemberCallExpr_trans trans_state si stmt_list expr_info =
let pln = trans_state.parent_line_number in
let context = trans_state.context in
(* First stmt is the method+this expr and the rest are params *)
let fun_exp_stmt, params_stmt = (match stmt_list with
| fe :: params -> fe, params
@ -773,8 +773,19 @@ struct
parent_line_number = line_number;
succ_nodes = [] } in
let result_trans_callee = instruction trans_state_callee fun_exp_stmt in
let function_type = CTypes_decl.get_type_from_expr_info expr_info context.CContext.tenv in
cxx_method_construct_call_trans trans_state_pri result_trans_callee fun_exp_stmt params_stmt
si expr_info
si function_type
and cxxConstructExpr_trans trans_state this_res_trans expr =
match expr with
| Clang_ast_t.CXXConstructExpr (si, params_stmt, ei, cxx_constr_info) ->
let trans_state_pri = PriorityNode.try_claim_priority_node trans_state si in
let decl_ref = cxx_constr_info.Clang_ast_t.xcei_decl_ref in
let res_trans_callee = decl_ref_trans trans_state this_res_trans si ei decl_ref in
cxx_method_construct_call_trans trans_state_pri res_trans_callee expr params_stmt si
Sil.Tvoid
| _ -> assert false
and objCMessageExpr_trans trans_state si obj_c_message_expr_info stmt_list expr_info =
Printing.log_out " priority node free = '%s'\n@."
@ -1477,6 +1488,11 @@ struct
| Some (InitListExpr (stmt_info , stmts , expr_info))
| Some (ExprWithCleanups (_, [InitListExpr (stmt_info , stmts , expr_info)], _, _)) ->
initListExpr_trans trans_state stmt_info expr_info stmts pvar
| Some (CXXConstructExpr _ as expr) ->
let typ_ptr = Sil.Tptr (typ, Sil.Pk_pointer) in
let this_exp = (Sil.Lvar pvar, typ_ptr) in
let this_res_trans = { empty_res_trans with exps = [this_exp] } in
cxxConstructExpr_trans trans_state this_res_trans expr
| Some ie -> (*For init expr, translate how to compute it and assign to the var*)
let sil_loc = CLocation.get_sil_location stmt_info pln context in
let trans_state_pri = PriorityNode.try_claim_priority_node trans_state stmt_info in

@ -665,6 +665,9 @@ let rec pointer_of_call_expr stmt =
| MemberExpr(_, _, _, member_expr_info) ->
let decl_ref = member_expr_info.Clang_ast_t.mei_decl_ref in
Some decl_ref.Clang_ast_t.dr_decl_pointer
| CXXConstructExpr (_, _, _, cxx_construct_expr_info) ->
let decl_ref = cxx_construct_expr_info.xcei_decl_ref in
Some decl_ref.Clang_ast_t.dr_decl_pointer
| _ ->
match snd (Clang_ast_proj.get_stmt_tuple stmt) with
| [stmt] -> pointer_of_call_expr stmt

@ -0,0 +1,25 @@
/*
* Copyright (c) 2015 - 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.
*/
class X {
int f;
public:
X(int a, int b = 0);
int div() { return 1 / f; }
};
X::X(int a, int b) {
f = a + b;
}
void test() {
X x1(0);
X x2(1);
X x3(0, 1);
}

@ -0,0 +1,43 @@
digraph iCFG {
11 [label="11: Call _fun_X_X \n _fun_X_X(&x1:class X *,0:int ,0:int ) [line 22]\n " shape="box"]
11 -> 10 ;
10 [label="10: Call _fun_X_X \n _fun_X_X(&x2:class X *,1:int ,0:int ) [line 23]\n " shape="box"]
10 -> 9 ;
9 [label="9: Call _fun_X_X \n _fun_X_X(&x3:class X *,0:int ,1:int ) [line 24]\n NULLIFY(&x1,false); [line 24]\n NULLIFY(&x2,false); [line 24]\n NULLIFY(&x3,false); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"]
9 -> 8 ;
8 [label="8: Exit test \n " color=yellow style=filled]
7 [label="7: Start test\nFormals: \nLocals: x3:class X x2:class X x1:class X \n DECLARE_LOCALS(&return,&x3,&x2,&x1); [line 21]\n " color=yellow style=filled]
7 -> 11 ;
6 [label="6: BinaryOperatorStmt: Assign \n n$0=*&this:class X * [line 18]\n n$1=*&a:int [line 18]\n n$2=*&b:int [line 18]\n *n$0.f:int =(n$1 + n$2) [line 18]\n REMOVE_TEMPS(n$0,n$1,n$2); [line 18]\n NULLIFY(&a,false); [line 18]\n NULLIFY(&b,false); [line 18]\n NULLIFY(&this,false); [line 18]\n APPLY_ABSTRACTION; [line 18]\n " shape="box"]
6 -> 5 ;
5 [label="5: Exit X_X \n " color=yellow style=filled]
4 [label="4: Start X_X\nFormals: this:class X * a:int b:int \nLocals: \n DECLARE_LOCALS(&return); [line 17]\n " color=yellow style=filled]
4 -> 6 ;
3 [label="3: Return Stmt \n n$0=*&this:class X * [line 14]\n n$1=*n$0.f:int [line 14]\n *&return:int =(1 / n$1) [line 14]\n REMOVE_TEMPS(n$0,n$1); [line 14]\n NULLIFY(&this,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"]
3 -> 2 ;
2 [label="2: Exit X_div \n " color=yellow style=filled]
1 [label="1: Start X_div\nFormals: this:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 14]\n " color=yellow style=filled]
1 -> 3 ;
}

@ -13,10 +13,11 @@ class X {
public:
X() {
init();
f = 3;
}
X(int a, int b);
int div() { return 1 / f; }
};
X::X(int a, int b) {
@ -24,3 +25,18 @@ X::X(int a, int b) {
init();
f = c;
}
void test_div0() {
X x(-2, 2);
x.div();
}
void test_div0_default_constructor() {
X x;
x.div();
}
void test_div1() {
X x(0, 1);
x.div();
}

@ -1,28 +1,80 @@
digraph iCFG {
12 [label="12: DeclStmt \n n$3=*&a:int [line 23]\n n$4=*&b:int [line 23]\n *&c:int =(n$3 + n$4) [line 23]\n REMOVE_TEMPS(n$3,n$4); [line 23]\n NULLIFY(&a,false); [line 23]\n NULLIFY(&b,false); [line 23]\n " shape="box"]
26 [label="26: Call _fun_X_X \n _fun_X_X(&x:class X *,0:int ,1:int ) [line 40]\n " shape="box"]
26 -> 25 ;
25 [label="25: Call _fun_X_div \n n$0=_fun_X_div(&x:class X &) [line 41]\n REMOVE_TEMPS(n$0); [line 41]\n NULLIFY(&x,false); [line 41]\n APPLY_ABSTRACTION; [line 41]\n " shape="box"]
25 -> 24 ;
24 [label="24: Exit test_div1 \n " color=yellow style=filled]
23 [label="23: Start test_div1\nFormals: \nLocals: x:class X \n DECLARE_LOCALS(&return,&x); [line 39]\n " color=yellow style=filled]
23 -> 26 ;
22 [label="22: Call _fun_X_X \n _fun_X_X(&x:class X *) [line 35]\n " shape="box"]
22 -> 21 ;
21 [label="21: Call _fun_X_div \n n$0=_fun_X_div(&x:class X &) [line 36]\n REMOVE_TEMPS(n$0); [line 36]\n NULLIFY(&x,false); [line 36]\n APPLY_ABSTRACTION; [line 36]\n " shape="box"]
21 -> 20 ;
20 [label="20: Exit test_div0_default_constructor \n " color=yellow style=filled]
19 [label="19: Start test_div0_default_constructor\nFormals: \nLocals: x:class X \n DECLARE_LOCALS(&return,&x); [line 34]\n " color=yellow style=filled]
19 -> 22 ;
18 [label="18: Call _fun_X_X \n _fun_X_X(&x:class X *,-2:int ,2:int ) [line 30]\n " shape="box"]
18 -> 17 ;
17 [label="17: Call _fun_X_div \n n$0=_fun_X_div(&x:class X &) [line 31]\n REMOVE_TEMPS(n$0); [line 31]\n NULLIFY(&x,false); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"]
17 -> 16 ;
16 [label="16: Exit test_div0 \n " color=yellow style=filled]
15 [label="15: Start test_div0\nFormals: \nLocals: x:class X \n DECLARE_LOCALS(&return,&x); [line 29]\n " color=yellow style=filled]
15 -> 18 ;
14 [label="14: DeclStmt \n n$3=*&a:int [line 24]\n n$4=*&b:int [line 24]\n *&c:int =(n$3 + n$4) [line 24]\n REMOVE_TEMPS(n$3,n$4); [line 24]\n NULLIFY(&a,false); [line 24]\n NULLIFY(&b,false); [line 24]\n " shape="box"]
14 -> 13 ;
13 [label="13: Call _fun_X_init \n n$2=*&this:class X * [line 25]\n _fun_X_init(n$2:class X ) [line 25]\n REMOVE_TEMPS(n$2); [line 25]\n " shape="box"]
13 -> 12 ;
12 [label="12: BinaryOperatorStmt: Assign \n n$0=*&this:class X * [line 26]\n n$1=*&c:int [line 26]\n *n$0.f:int =n$1 [line 26]\n REMOVE_TEMPS(n$0,n$1); [line 26]\n NULLIFY(&c,false); [line 26]\n NULLIFY(&this,false); [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"]
12 -> 11 ;
11 [label="11: Call _fun_X_init \n n$2=*&this:class X * [line 24]\n _fun_X_init(n$2:class X ) [line 24]\n REMOVE_TEMPS(n$2); [line 24]\n " shape="box"]
11 [label="11: Exit X_X \n " color=yellow style=filled]
11 -> 10 ;
10 [label="10: BinaryOperatorStmt: Assign \n n$0=*&this:class X * [line 25]\n n$1=*&c:int [line 25]\n *n$0.f:int =n$1 [line 25]\n REMOVE_TEMPS(n$0,n$1); [line 25]\n NULLIFY(&c,false); [line 25]\n NULLIFY(&this,false); [line 25]\n APPLY_ABSTRACTION; [line 25]\n " shape="box"]
10 [label="10: Start X_X\nFormals: this:class X * a:int b:int \nLocals: c:int \n DECLARE_LOCALS(&return,&c); [line 23]\n NULLIFY(&c,false); [line 23]\n " color=yellow style=filled]
10 -> 9 ;
9 [label="9: Exit X_X \n " color=yellow style=filled]
10 -> 14 ;
9 [label="9: Return Stmt \n n$0=*&this:class X * [line 20]\n n$1=*n$0.f:int [line 20]\n *&return:int =(1 / n$1) [line 20]\n REMOVE_TEMPS(n$0,n$1); [line 20]\n NULLIFY(&this,false); [line 20]\n APPLY_ABSTRACTION; [line 20]\n " shape="box"]
8 [label="8: Start X_X\nFormals: this:class X * a:int b:int \nLocals: c:int \n DECLARE_LOCALS(&return,&c); [line 22]\n NULLIFY(&c,false); [line 22]\n " color=yellow style=filled]
9 -> 8 ;
8 [label="8: Exit X_div \n " color=yellow style=filled]
8 -> 12 ;
7 [label="7: Call _fun_X_init \n n$1=*&this:class X * [line 15]\n _fun_X_init(n$1:class X ) [line 15]\n REMOVE_TEMPS(n$1); [line 15]\n " shape="box"]
7 [label="7: Start X_div\nFormals: this:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 20]\n " color=yellow style=filled]
7 -> 6 ;
6 [label="6: BinaryOperatorStmt: Assign \n n$0=*&this:class X * [line 16]\n *n$0.f:int =3 [line 16]\n REMOVE_TEMPS(n$0); [line 16]\n NULLIFY(&this,false); [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"]
7 -> 9 ;
6 [label="6: Call _fun_X_init \n n$0=*&this:class X * [line 15]\n _fun_X_init(n$0:class X ) [line 15]\n REMOVE_TEMPS(n$0); [line 15]\n NULLIFY(&this,false); [line 15]\n APPLY_ABSTRACTION; [line 15]\n " shape="box"]
6 -> 5 ;
@ -32,7 +84,7 @@ digraph iCFG {
4 [label="4: Start X_X\nFormals: this:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 14]\n " color=yellow style=filled]
4 -> 7 ;
4 -> 6 ;
3 [label="3: BinaryOperatorStmt: Assign \n n$0=*&this:class X * [line 12]\n *n$0.f:int =0 [line 12]\n REMOVE_TEMPS(n$0); [line 12]\n NULLIFY(&this,false); [line 12]\n APPLY_ABSTRACTION; [line 12]\n " shape="box"]

@ -1,4 +1,51 @@
digraph iCFG {
24 [label="24: Call _fun_foo::foo::my_record_ \n _fun_foo::foo::my_record_(&x:struct foo::foo::my_record *) [line 45]\n " shape="box"]
24 -> 23 ;
23 [label="23: Call _fun_bar::Rectangle_Rectangle \n _fun_bar::Rectangle_Rectangle(&rect1:class bar::Rectangle *) [line 47]\n " shape="box"]
23 -> 22 ;
22 [label="22: Call _fun_bar::Rectangle_set_values \n _fun_bar::Rectangle_set_values(&rect1:class bar::Rectangle &,3:int ,4:int ) [line 48]\n " shape="box"]
22 -> 21 ;
21 [label="21: Call _fun_foo::Rectangle_Rectangle \n _fun_foo::Rectangle_Rectangle(&rect2:class foo::Rectangle *) [line 50]\n " shape="box"]
21 -> 20 ;
20 [label="20: Call _fun_foo::Rectangle_set_values \n _fun_foo::Rectangle_set_values(&rect2:class foo::Rectangle &,7:int ,10:int ) [line 51]\n " shape="box"]
20 -> 19 ;
19 [label="19: BinaryOperatorStmt: Assign \n *&x.a:int =10 [line 54]\n " shape="box"]
19 -> 18 ;
18 [label="18: BinaryOperatorStmt: Assign \n n$2=_fun_value() [line 55]\n *&i:int =n$2 [line 55]\n REMOVE_TEMPS(n$2); [line 55]\n NULLIFY(&i,false); [line 55]\n " shape="box"]
18 -> 17 ;
17 [label="17: BinaryOperatorStmt: Assign \n n$1=_fun_value() [line 56]\n *&i:int =n$1 [line 56]\n REMOVE_TEMPS(n$1); [line 56]\n NULLIFY(&i,false); [line 56]\n " shape="box"]
17 -> 16 ;
16 [label="16: BinaryOperatorStmt: Assign \n n$0=*&#GB$pi:double [line 57]\n *&j:double =n$0 [line 57]\n REMOVE_TEMPS(n$0); [line 57]\n NULLIFY(&j,false); [line 57]\n " shape="box"]
16 -> 15 ;
15 [label="15: Return Stmt \n *&return:int =0 [line 58]\n NULLIFY(&rect1,false); [line 58]\n NULLIFY(&rect2,false); [line 58]\n NULLIFY(&x,false); [line 58]\n APPLY_ABSTRACTION; [line 58]\n " shape="box"]
15 -> 14 ;
14 [label="14: Exit main \n " color=yellow style=filled]
13 [label="13: Start main\nFormals: \nLocals: rect2:class foo::Rectangle rect1:class bar::Rectangle x:struct foo::foo::my_record j:double i:int \n DECLARE_LOCALS(&return,&rect2,&rect1,&x,&j,&i); [line 40]\n NULLIFY(&i,false); [line 40]\n NULLIFY(&j,false); [line 40]\n " color=yellow style=filled]
13 -> 24 ;
12 [label="12: Exit bar::Rectangle_Rectangle \n " color=yellow style=filled]

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015 - 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;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsErrorInMethod.contains;
import static utils.matchers.ResultContainsNoErrorInMethod.doesNotContain;
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 ConstructorWithBodyTest {
public static final String FILE =
"infer/tests/codetoanalyze/cpp/frontend/constructors/constructor_with_body.cpp";
private static ImmutableList<String> inferCmd;
public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO";
@ClassRule
public static DebuggableTemporaryFolder folder =
new DebuggableTemporaryFolder();
@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferCmd = InferRunner.createCPPInferCommand(folder, FILE);
}
@Test
public void whenInferRunsOnConstructorWithBodyDiv0ErrorIsFound()
throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferCPP(inferCmd);
String[] procedures = {
"test_div0",
"test_div0_default_constructor",
};
assertThat(
"Results should contain null pointer dereference error",
inferResults,
contains(
DIVIDE_BY_ZERO,
FILE,
"test_div0"
)
);
assertThat(
"Results should contain null pointer dereference error",
inferResults,
contains(
DIVIDE_BY_ZERO,
FILE,
"test_div0_default_constructor"
)
);
}
@Test
public void whenInferRunsOnConstructorWithBodyDiv1ErrorIsNotFound()
throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferCPP(inferCmd);
assertThat(
"Results should not contain null pointer dereference error",
inferResults,
doesNotContain(
DIVIDE_BY_ZERO,
FILE,
"test_div1"
)
);
}
}

@ -30,9 +30,14 @@ public class ConstructorsTest {
}
@Test
public void testInlineMethodDotFilesMatch()
public void testConstructorWithBodyDotFilesMatch()
throws InterruptedException, IOException, InferException {
frontendTest("constructor_with_body.cpp");
}
@Test
public void testConstructorDefaultArgDotFilesMatch()
throws InterruptedException, IOException, InferException {
frontendTest("constructor_default_arg.cpp");
}
}

Loading…
Cancel
Save