Translate initializing arrays of C++ classes

Reviewed By: akotulski

Differential Revision: D3145398

fb-gh-sync-id: 57b9a44
fbshipit-source-id: 57b9a44
master
Dulma Rodriguez 9 years ago committed by Facebook Github Bot 1
parent b5b4d436ba
commit bc3134dd32

@ -900,6 +900,12 @@ let is_cpp_class typ =
let is_java_class typ = let is_java_class typ =
is_class_of_kind typ Csu.Java is_class_of_kind typ Csu.Java
let rec is_array_of_cpp_class typ =
match typ with
| Tarray (typ, _) ->
is_array_of_cpp_class typ
| _ -> is_cpp_class typ
(** turn a *T into a T. fails if [typ] is not a pointer type *) (** turn a *T into a T. fails if [typ] is not a pointer type *)
let typ_strip_ptr = function let typ_strip_ptr = function
| Tptr (t, _) -> t | Tptr (t, _) -> t
@ -1438,6 +1444,12 @@ let typ_equal t1 t2 =
let exp_equal e1 e2 = let exp_equal e1 e2 =
exp_compare e1 e2 = 0 exp_compare e1 e2 = 0
let rec exp_is_array_index_of exp1 exp2 =
match exp1 with
| Lindex (exp, _) ->
exp_is_array_index_of exp exp2
| _ -> exp_equal exp1 exp2
let ident_exp_compare = let ident_exp_compare =
pair_compare Ident.compare exp_compare pair_compare Ident.compare exp_compare

@ -561,6 +561,8 @@ val is_cpp_class : typ -> bool
val is_java_class : typ -> bool val is_java_class : typ -> bool
val is_array_of_cpp_class : typ -> bool
val exp_is_zero : exp -> bool val exp_is_zero : exp -> bool
val exp_is_null_literal : exp -> bool val exp_is_null_literal : exp -> bool
@ -667,6 +669,9 @@ val exp_compare : exp -> exp -> int
val exp_equal : exp -> exp -> bool val exp_equal : exp -> exp -> bool
(** exp_is_array_index_of index arr returns true is index is an array index of arr. *)
val exp_is_array_index_of : exp -> exp -> bool
val call_flags_compare : call_flags -> call_flags -> int val call_flags_compare : call_flags -> call_flags -> int
val exp_typ_compare : (exp * typ) -> (exp * typ) -> int val exp_typ_compare : (exp * typ) -> (exp * typ) -> int

@ -200,6 +200,9 @@ struct
let collect_exprs res_trans_list = let collect_exprs res_trans_list =
IList.flatten (IList.map (fun res_trans -> res_trans.exps) res_trans_list) IList.flatten (IList.map (fun res_trans -> res_trans.exps) res_trans_list)
let collect_initid_exprs res_trans_list =
IList.flatten (IList.map (fun res_trans -> res_trans.initd_exps) res_trans_list)
(* If e is a block and the calling node has the priority then *) (* If e is a block and the calling node has the priority then *)
(* we need to release the priority to allow*) (* we need to release the priority to allow*)
(* creation of nodes inside the block.*) (* creation of nodes inside the block.*)
@ -1590,6 +1593,26 @@ struct
let loop = Clang_ast_t.WhileStmt (stmt_info, [null_stmt; cond; body']) in let loop = Clang_ast_t.WhileStmt (stmt_info, [null_stmt; cond; body']) in
instruction trans_state (Clang_ast_t.CompoundStmt (stmt_info, [assign_next_object; loop])) instruction trans_state (Clang_ast_t.CompoundStmt (stmt_info, [assign_next_object; loop]))
and initListExpr_initializers_trans trans_state var_exp n stmts typ =
let (var_exp_inside, typ_inside) = match typ with
| Sil.Tarray (t, _) when Sil.is_array_of_cpp_class typ ->
Sil.Lindex (var_exp, Sil.Const (Sil.Cint (Sil.Int.of_int n))), t
| _ -> var_exp, typ in
let trans_state' = { trans_state with var_exp_typ = Some (var_exp_inside, typ_inside) } in
match stmts with
| [] -> []
| stmt :: rest ->
let rest_stmts_res_trans =
initListExpr_initializers_trans trans_state var_exp (n + 1) rest typ in
match stmt with
| Clang_ast_t.InitListExpr (_ , stmts , _) ->
let inside_stmts_res_trans =
initListExpr_initializers_trans trans_state var_exp_inside 0 stmts typ_inside in
inside_stmts_res_trans @ rest_stmts_res_trans
| _ ->
let stmt_res_trans = instruction trans_state' stmt in
stmt_res_trans :: rest_stmts_res_trans
and initListExpr_trans trans_state stmt_info expr_info stmts = and initListExpr_trans trans_state stmt_info expr_info stmts =
let context = trans_state.context in let context = trans_state.context in
let tenv = context.tenv in let tenv = context.tenv in
@ -1604,11 +1627,7 @@ struct
let var_type = let var_type =
CTypes_decl.type_ptr_to_sil_type context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in CTypes_decl.type_ptr_to_sil_type context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in
let lh = var_or_zero_in_init_list tenv var_exp var_type ~return_zero:false in let lh = var_or_zero_in_init_list tenv var_exp var_type ~return_zero:false in
let rec collect_right_hand_exprs stmt = match stmt with let res_trans_subexpr_list = initListExpr_initializers_trans trans_state var_exp 0 stmts typ in
| Clang_ast_t.InitListExpr (_ , stmts , _) ->
CTrans_utils.collect_res_trans (IList.map collect_right_hand_exprs stmts)
| _ -> instruction trans_state stmt in
let res_trans_subexpr_list = IList.map collect_right_hand_exprs stmts in
let rh_exps = collect_exprs res_trans_subexpr_list in let rh_exps = collect_exprs res_trans_subexpr_list in
if IList.length rh_exps == 0 then if IList.length rh_exps == 0 then
let exp = Sil.zero_value_of_numerical_type var_type in let exp = Sil.zero_value_of_numerical_type var_type in
@ -1624,7 +1643,17 @@ struct
if IList.length rh_exps == IList.length lh then if IList.length rh_exps == IList.length lh then
(* Creating new instructions by assigning right hand side to left hand side expressions *) (* Creating new instructions by assigning right hand side to left hand side expressions *)
let assign_instr (lh_exp, lh_t) (rh_exp, _) = Sil.Set (lh_exp, lh_t, rh_exp, sil_loc) in let assign_instr (lh_exp, lh_t) (rh_exp, _) = Sil.Set (lh_exp, lh_t, rh_exp, sil_loc) in
let assign_instrs = IList.map2 assign_instr lh rh_exps in let assign_instrs =
let initd_exps = collect_initid_exprs res_trans_subexpr_list in
(* If the variable var_exp is of type array, and some of its indices were initialized *)
(* by some constructor call, which we can tell by the fact that the index is returned *)
(* in initd_exps, then we assume that all the indices were initialized and *)
(* we don't need any assignments. *)
if IList.exists
((fun arr index -> Sil.exp_is_array_index_of index arr) var_exp)
initd_exps
then []
else IList.map2 assign_instr lh rh_exps in
let initlist_expr_res = let initlist_expr_res =
{ empty_res_trans with { empty_res_trans with
exps = [(var_exp, var_type)]; exps = [(var_exp, var_type)];

@ -0,0 +1,43 @@
/*
* 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.
*/
class Person {
public:
Person(int i) { x = i; }
Person() {}
int x;
};
int array_of_person() {
Person arr[10] = {Person(), Person(), Person()};
return (arr[0]).x;
}
int matrix_of_person() {
Person arr[2][2] = {Person(), Person(), Person(), Person()};
return (arr[0][1]).x;
}
struct Z {
int a;
int b;
};
void initialization_c_style() {
struct Z z[2] = {{1, 2}, {2, 3}};
struct Z z2;
}
// Our handling assumes that either all the array elements are initialised
// with a constructor or not, so this doesn't work.
void initialization_mixed_styles_not_handled_correctly() {
struct Z old;
struct Z z[2] = {{1, 2}, old};
struct Z z2;
}

@ -0,0 +1,117 @@
digraph iCFG {
31 [label="31: DeclStmt \n _fun_Z_Z(&old:class Z *) [line 40]\n " shape="box"]
31 -> 30 ;
30 [label="30: DeclStmt \n _fun_Z_Z(&z[1]:class Z *,&old:class Z &) [line 41]\n " shape="box"]
30 -> 29 ;
29 [label="29: DeclStmt \n _fun_Z_Z(&z2:class Z *) [line 42]\n NULLIFY(&old,false); [line 42]\n NULLIFY(&z,false); [line 42]\n NULLIFY(&z2,false); [line 42]\n APPLY_ABSTRACTION; [line 42]\n " shape="box"]
29 -> 28 ;
28 [label="28: Exit initialization_mixed_styles_not_handled_correctly \n " color=yellow style=filled]
27 [label="27: Start initialization_mixed_styles_not_handled_correctly\nFormals: \nLocals: z2:class Z z:class Z [2] old:class Z \n DECLARE_LOCALS(&return,&z2,&z,&old); [line 39]\n " color=yellow style=filled]
27 -> 31 ;
26 [label="26: DeclStmt \n *&z[0].a:int =1 [line 33]\n *&z[0].b:int =2 [line 33]\n *&z[1].a:int =2 [line 33]\n *&z[1].b:int =3 [line 33]\n " shape="box"]
26 -> 25 ;
25 [label="25: DeclStmt \n _fun_Z_Z(&z2:class Z *) [line 34]\n NULLIFY(&z2,false); [line 34]\n APPLY_ABSTRACTION; [line 34]\n " shape="box"]
25 -> 24 ;
24 [label="24: Exit initialization_c_style \n " color=yellow style=filled]
23 [label="23: Start initialization_c_style\nFormals: \nLocals: z2:class Z z:class Z [2] \n DECLARE_LOCALS(&return,&z2,&z); [line 32]\n NULLIFY(&z,false); [line 32]\n " color=yellow style=filled]
23 -> 26 ;
22 [label="22: Constructor Init \n n$3=*&this:class Z * [line 27]\n n$4=*&__param_0:class Z & [line 27]\n n$5=*n$4.a:int [line 27]\n *n$3.a:int =n$5 [line 27]\n REMOVE_TEMPS(n$3,n$4,n$5); [line 27]\n " shape="box"]
22 -> 21 ;
21 [label="21: Constructor Init \n n$0=*&this:class Z * [line 27]\n n$1=*&__param_0:class Z & [line 27]\n n$2=*n$1.b:int [line 27]\n *n$0.b:int =n$2 [line 27]\n REMOVE_TEMPS(n$0,n$1,n$2); [line 27]\n NULLIFY(&__param_0,false); [line 27]\n NULLIFY(&this,false); [line 27]\n APPLY_ABSTRACTION; [line 27]\n " shape="box"]
21 -> 20 ;
20 [label="20: Exit Z_Z \n " color=yellow style=filled]
19 [label="19: Start Z_Z\nFormals: this:class Z * __param_0:class Z &\nLocals: \n DECLARE_LOCALS(&return); [line 27]\n " color=yellow style=filled]
19 -> 22 ;
18 [label="18: Exit Z_Z \n " color=yellow style=filled]
17 [label="17: Start Z_Z\nFormals: this:class Z *\nLocals: \n DECLARE_LOCALS(&return); [line 27]\n NULLIFY(&this,false); [line 27]\n " color=yellow style=filled]
17 -> 18 ;
16 [label="16: DeclStmt \n _fun_Person_Person(&SIL_materialize_temp__n$4:class Person *) [line 23]\n _fun_Person_Person(&arr[0][0]:class Person *,&SIL_materialize_temp__n$4:class Person &) [line 23]\n _fun_Person_Person(&SIL_materialize_temp__n$3:class Person *) [line 23]\n _fun_Person_Person(&arr[0][1]:class Person *,&SIL_materialize_temp__n$3:class Person &) [line 23]\n _fun_Person_Person(&SIL_materialize_temp__n$2:class Person *) [line 23]\n _fun_Person_Person(&arr[1][0]:class Person *,&SIL_materialize_temp__n$2:class Person &) [line 23]\n _fun_Person_Person(&SIL_materialize_temp__n$1:class Person *) [line 23]\n _fun_Person_Person(&arr[1][1]:class Person *,&SIL_materialize_temp__n$1:class Person &) [line 23]\n " shape="box"]
16 -> 15 ;
15 [label="15: Return Stmt \n n$0=*&arr[0][1].x:int [line 24]\n *&return:int =n$0 [line 24]\n REMOVE_TEMPS(n$0); [line 24]\n NULLIFY(&SIL_materialize_temp__n$1,false); [line 24]\n NULLIFY(&SIL_materialize_temp__n$2,false); [line 24]\n NULLIFY(&SIL_materialize_temp__n$3,false); [line 24]\n NULLIFY(&SIL_materialize_temp__n$4,false); [line 24]\n NULLIFY(&arr,false); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"]
15 -> 14 ;
14 [label="14: Exit matrix_of_person \n " color=yellow style=filled]
13 [label="13: Start matrix_of_person\nFormals: \nLocals: arr:class Person [2][2] SIL_materialize_temp__n$1:class Person SIL_materialize_temp__n$2:class Person SIL_materialize_temp__n$3:class Person SIL_materialize_temp__n$4:class Person \n DECLARE_LOCALS(&return,&arr,&SIL_materialize_temp__n$1,&SIL_materialize_temp__n$2,&SIL_materialize_temp__n$3,&SIL_materialize_temp__n$4); [line 22]\n " color=yellow style=filled]
13 -> 16 ;
12 [label="12: DeclStmt \n _fun_Person_Person(&SIL_materialize_temp__n$3:class Person *) [line 18]\n _fun_Person_Person(&arr[0]:class Person *,&SIL_materialize_temp__n$3:class Person &) [line 18]\n _fun_Person_Person(&SIL_materialize_temp__n$2:class Person *) [line 18]\n _fun_Person_Person(&arr[1]:class Person *,&SIL_materialize_temp__n$2:class Person &) [line 18]\n _fun_Person_Person(&SIL_materialize_temp__n$1:class Person *) [line 18]\n _fun_Person_Person(&arr[2]:class Person *,&SIL_materialize_temp__n$1:class Person &) [line 18]\n " shape="box"]
12 -> 11 ;
11 [label="11: Return Stmt \n n$0=*&arr[0].x:int [line 19]\n *&return:int =n$0 [line 19]\n REMOVE_TEMPS(n$0); [line 19]\n NULLIFY(&SIL_materialize_temp__n$1,false); [line 19]\n NULLIFY(&SIL_materialize_temp__n$2,false); [line 19]\n NULLIFY(&SIL_materialize_temp__n$3,false); [line 19]\n NULLIFY(&arr,false); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"]
11 -> 10 ;
10 [label="10: Exit array_of_person \n " color=yellow style=filled]
9 [label="9: Start array_of_person\nFormals: \nLocals: arr:class Person [10] SIL_materialize_temp__n$1:class Person SIL_materialize_temp__n$2:class Person SIL_materialize_temp__n$3:class Person \n DECLARE_LOCALS(&return,&arr,&SIL_materialize_temp__n$1,&SIL_materialize_temp__n$2,&SIL_materialize_temp__n$3); [line 17]\n " color=yellow style=filled]
9 -> 12 ;
8 [label="8: Constructor Init \n n$0=*&this:class Person * [line 10]\n n$1=*&__param_0:class Person & [line 10]\n n$2=*n$1.x:int [line 10]\n *n$0.x:int =n$2 [line 10]\n REMOVE_TEMPS(n$0,n$1,n$2); [line 10]\n NULLIFY(&__param_0,false); [line 10]\n NULLIFY(&this,false); [line 10]\n APPLY_ABSTRACTION; [line 10]\n " shape="box"]
8 -> 7 ;
7 [label="7: Exit Person_Person \n " color=yellow style=filled]
6 [label="6: Start Person_Person\nFormals: this:class Person * __param_0:class Person &\nLocals: \n DECLARE_LOCALS(&return); [line 10]\n " color=yellow style=filled]
6 -> 8 ;
5 [label="5: Exit Person_Person \n " color=yellow style=filled]
4 [label="4: Start Person_Person\nFormals: this:class Person *\nLocals: \n DECLARE_LOCALS(&return); [line 13]\n NULLIFY(&this,false); [line 13]\n " color=yellow style=filled]
4 -> 5 ;
3 [label="3: BinaryOperatorStmt: Assign \n n$0=*&this:class Person * [line 12]\n n$1=*&i:int [line 12]\n *n$0.x:int =n$1 [line 12]\n REMOVE_TEMPS(n$0,n$1); [line 12]\n NULLIFY(&i,false); [line 12]\n NULLIFY(&this,false); [line 12]\n APPLY_ABSTRACTION; [line 12]\n " shape="box"]
3 -> 2 ;
2 [label="2: Exit Person_Person \n " color=yellow style=filled]
1 [label="1: Start Person_Person\nFormals: this:class Person * i:int \nLocals: \n DECLARE_LOCALS(&return); [line 12]\n " color=yellow style=filled]
1 -> 3 ;
}

@ -7,7 +7,7 @@ digraph iCFG {
7 -> 6 ; 7 -> 6 ;
6 [label="6: DeclStmt \n n$0=*&c1:class C * [line 24]\n n$1=_fun_NSObject_init(n$0:class C *) virtual [line 24]\n n$2=*&c1:class C * [line 24]\n n$3=*&c2:class C * [line 24]\n *&a[0]:class C *=n$1 [line 24]\n *&a[1]:class C *=n$2 [line 24]\n *&a[2]:class C *=n$3 [line 24]\n REMOVE_TEMPS(n$0,n$1,n$2,n$3); [line 24]\n NULLIFY(&c1,false); [line 24]\n NULLIFY(&c2,false); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"] 6 [label="6: DeclStmt \n n$2=*&c1:class C * [line 24]\n n$3=_fun_NSObject_init(n$2:class C *) virtual [line 24]\n n$1=*&c1:class C * [line 24]\n n$0=*&c2:class C * [line 24]\n *&a[0]:class C *=n$3 [line 24]\n *&a[1]:class C *=n$1 [line 24]\n *&a[2]:class C *=n$0 [line 24]\n REMOVE_TEMPS(n$2,n$3,n$1,n$0); [line 24]\n NULLIFY(&c1,false); [line 24]\n NULLIFY(&c2,false); [line 24]\n APPLY_ABSTRACTION; [line 24]\n " shape="box"]
6 -> 5 ; 6 -> 5 ;

@ -82,4 +82,10 @@ public class ConstructorsTest {
throws InterruptedException, IOException, InferException { throws InterruptedException, IOException, InferException {
frontendTest("constructor_new.cpp"); frontendTest("constructor_new.cpp");
} }
@Test
public void testConstructorArrayFilesMatch()
throws InterruptedException, IOException, InferException {
frontendTest("constructor_array.cpp");
}
} }

Loading…
Cancel
Save