Fix problems with translation of InitListExpr

Reviewed By: akotulski

Differential Revision: D2971312

fb-gh-sync-id: 826a70f
shipit-source-id: 826a70f
master
Dulma Rodriguez 9 years ago committed by facebook-github-bot-1
parent 9d080cadb1
commit 4264e94565

@ -677,80 +677,77 @@ struct
(* Note the order of res_trans_idx.ids @ res_trans_a.ids is important. *)
(* We expect to use only res_trans_idx.ids in construction of other operation. *)
(* res_trans_a.ids is passed to be Removed.*)
{ root_nodes = root_nodes;
leaf_nodes = leaf_nodes;
{ empty_res_trans with
root_nodes;
leaf_nodes;
ids = res_trans_idx.ids @ res_trans_a.ids;
instrs = res_trans_a.instrs @ res_trans_idx.instrs;
exps = [(array_exp, typ)];
initd_exps = res_trans_idx.initd_exps @ res_trans_a.initd_exps;
is_cpp_call_virtual = false;}
initd_exps = res_trans_idx.initd_exps @ res_trans_a.initd_exps; }
and binaryOperator_trans trans_state binary_operator_info stmt_info expr_info stmt_list =
let open Clang_ast_t in
let procname = Cfg.Procdesc.get_proc_name trans_state.context.CContext.procdesc in
let bok = (Clang_ast_j.string_of_binary_operator_kind binary_operator_info.Clang_ast_t.boi_kind) in
Printing.log_out " BinaryOperator '%s' " bok;
Printing.log_out " priority node free = '%s'\n@."
(string_of_bool (PriorityNode.is_priority_free trans_state));
let context = trans_state.context in
let trans_state_pri = PriorityNode.try_claim_priority_node trans_state stmt_info in
let nname = "BinaryOperatorStmt: "^ (CArithmetic_trans.bin_op_to_string binary_operator_info) in
let trans_state' = { trans_state_pri with succ_nodes = [] } in
let sil_loc = CLocation.get_sil_location stmt_info context in
let typ = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in
(match stmt_list with
| [s1; ImplicitCastExpr (_, [CompoundLiteralExpr (_, stmts, expr_info)], _, _)] ->
let decl_ref = get_decl_ref_info s1 in
let pvar = CVar_decl.sil_var_of_decl_ref context decl_ref procname in
let trans_state' = { trans_state with var_exp_typ = Some (Sil.Lvar pvar, typ) } in
let res_trans_tmp =
initListExpr_trans trans_state' stmt_info expr_info stmts in
{ res_trans_tmp with leaf_nodes =[]}
| [s1; s2] -> (* Assumption: We expect precisely 2 stmt corresponding to the 2 operands*)
let rhs_owning_method = CTrans_utils.is_owning_method s2 in
(* NOTE: we create a node only if required. In that case this node *)
(* becomes the successor of the nodes that may be created when *)
(* translating the operands. *)
let trans_state_pri = PriorityNode.try_claim_priority_node trans_state stmt_info in
let trans_state' = { trans_state_pri with succ_nodes = [] } in
let res_trans_e1 = exec_with_self_exception instruction trans_state' s1 in
let (var_exp, var_exp_typ) = extract_exp_from_list res_trans_e1.exps
"\nWARNING: Missing LHS operand in BinOp. Returning -1. Fix needed...\n" in
let trans_state'' = { trans_state' with var_exp_typ = Some (var_exp, var_exp_typ) } in
let res_trans_e2 =
(* translation of s2 is done taking care of block special case *)
exec_with_block_priority_exception (exec_with_self_exception instruction) trans_state' s2 stmt_info in
let (sil_e1, sil_typ1) = extract_exp_from_list res_trans_e1.exps "\nWARNING: Missing LHS operand in BinOp. Returning -1. Fix needed...\n" in
let (sil_e2, _) =
extract_exp_from_list res_trans_e2.exps
exec_with_block_priority_exception (exec_with_self_exception instruction) trans_state''
s2 stmt_info in
let (sil_e2, _) = extract_exp_from_list res_trans_e2.exps
"\nWARNING: Missing RHS operand in BinOp. Returning -1. Fix needed...\n" in
let exp_op, instr_bin, ids_bin =
CArithmetic_trans.binary_operation_instruction context binary_operator_info sil_e1 typ sil_e2 sil_loc rhs_owning_method in
(* Create a node if the priority if free and there are instructions *)
let creating_node =
(PriorityNode.own_priority_node trans_state_pri.priority stmt_info) &&
(IList.length instr_bin >0) in
let extra_instrs, extra_ids, exp_to_parent =
if (is_binary_assign_op binary_operator_info)
(* assignment operator result is lvalue in CPP, rvalue in C, hence the difference *)
&& (not (General_utils.is_cpp_translation !CFrontend_config.language))
&& ((not creating_node) || (is_return_temp trans_state.continuation)) then (
(* We are in this case when an assignment is inside *)
(* another operator that creates a node. Eg. another *)
(* assignment. *)
(* As no node is created here ids are passed to the parent *)
let id = Ident.create_fresh Ident.knormal in
let res_instr = Sil.Letderef (id, sil_e1, sil_typ1, sil_loc) in
[res_instr], [id], Sil.Var id
) else (
[], [], exp_op) in
let binop_res_trans = { empty_res_trans with
ids = ids_bin @ extra_ids;
instrs = instr_bin @ extra_instrs
} in
let all_res_trans = [res_trans_e1; res_trans_e2; binop_res_trans] in
let nname = "BinaryOperatorStmt: "^ (CArithmetic_trans.bin_op_to_string binary_operator_info) in
let res_trans_to_parent = PriorityNode.compute_results_to_parent trans_state_pri sil_loc nname stmt_info all_res_trans in
{ res_trans_to_parent with exps = [(exp_to_parent, sil_typ1)] }
| _ -> assert false) (* Binary operator should have two operands*)
let binop_res_trans, exp_to_parent =
if IList.exists (Sil.exp_equal var_exp) res_trans_e2.initd_exps then [], []
else
let exp_op, instr_bin, ids_bin = CArithmetic_trans.binary_operation_instruction
context binary_operator_info var_exp typ sil_e2 sil_loc rhs_owning_method in
(* Create a node if the priority if free and there are instructions *)
let creating_node =
(PriorityNode.own_priority_node trans_state_pri.priority stmt_info) &&
(IList.length instr_bin >0) in
let extra_instrs, extra_ids, exp_to_parent =
if (is_binary_assign_op binary_operator_info)
(* assignment operator result is lvalue in CPP, rvalue in C, *)
(* hence the difference *)
&& (not (General_utils.is_cpp_translation !CFrontend_config.language))
&& ((not creating_node) || (is_return_temp trans_state.continuation)) then (
(* We are in this case when an assignment is inside *)
(* another operator that creates a node. Eg. another *)
(* assignment. *)
(* As no node is created here ids are passed to the parent *)
let id = Ident.create_fresh Ident.knormal in
let res_instr = Sil.Letderef (id, var_exp, var_exp_typ, sil_loc) in
[res_instr], [id], Sil.Var id
) else (
[], [], exp_op) in
let binop_res_trans = { empty_res_trans with
ids = ids_bin @ extra_ids;
instrs = instr_bin @ extra_instrs
} in
[binop_res_trans], [(exp_to_parent, var_exp_typ)] in
let all_res_trans = [res_trans_e1; res_trans_e2] @ binop_res_trans in
let res_trans_to_parent = PriorityNode.compute_results_to_parent trans_state_pri sil_loc
nname stmt_info all_res_trans in
{ res_trans_to_parent with exps = exp_to_parent }
| _ -> assert false) (* Binary operator should have two operands *)
and callExpr_trans trans_state si stmt_list expr_info =
let context = trans_state.context in
@ -1095,13 +1092,13 @@ struct
Sil.Letderef (id, Sil.Lvar pvar, var_typ, sil_loc);
Sil.Nullify (pvar, sil_loc, true)
] in
{ root_nodes = res_trans_cond.root_nodes;
{ empty_res_trans with
root_nodes = res_trans_cond.root_nodes;
leaf_nodes = [join_node];
ids = [id];
instrs = instrs;
exps = [(Sil.Var id, typ)];
initd_exps = []; (* TODO we should get exps from branches+cond *)
is_cpp_call_virtual = false;
}
| _ -> assert false)
@ -1135,13 +1132,12 @@ struct
let rnodes = if (IList.length res_trans_cond.root_nodes) = 0 then
[prune_t; prune_f]
else res_trans_cond.root_nodes in
{ root_nodes = rnodes;
{ empty_res_trans with
root_nodes = rnodes;
leaf_nodes = [prune_t; prune_f];
ids = res_trans_cond.ids;
instrs = instrs';
exps = e';
initd_exps = [];
is_cpp_call_virtual = false;
} in
(* This function translate (s1 binop s2) doing shortcircuit for '&&' and '||' *)
@ -1169,13 +1165,12 @@ struct
let (exp1, typ1) = extract_exp res_trans_s1.exps in
let (exp2, _) = extract_exp res_trans_s2.exps in
let e_cond = Sil.BinOp (binop, exp1, exp2) in
{ root_nodes = root_nodes_to_parent;
{ empty_res_trans with
root_nodes = root_nodes_to_parent;
leaf_nodes = prune_to_short_c@res_trans_s2.leaf_nodes;
ids = res_trans_s1.ids@res_trans_s2.ids;
instrs = res_trans_s1.instrs@res_trans_s2.instrs;
exps = [(e_cond, typ1)];
initd_exps = [];
is_cpp_call_virtual = false;
} in
Printing.log_out "Translating Condition for Conditional/Loop \n";
let open Clang_ast_t in
@ -1228,14 +1223,10 @@ struct
(* Note: by contruction prune nodes are leafs_nodes_cond *)
let ids_t = do_branch true stmt1 res_trans_cond.leaf_nodes in
let ids_f = do_branch false stmt2 res_trans_cond.leaf_nodes in
{
{ empty_res_trans with
root_nodes = res_trans_decl.root_nodes;
leaf_nodes = [join_node];
ids = res_trans_decl.ids @ res_trans_cond.ids @ ids_t @ ids_f;
instrs = [];
exps = [];
initd_exps = [];
is_cpp_call_virtual = false;
}
| _ -> assert false)
@ -1514,6 +1505,7 @@ struct
instruction trans_state (Clang_ast_t.CompoundStmt (stmt_info, [assign_next_object; loop]))
and initListExpr_trans trans_state stmt_info expr_info stmts =
let open General_utils in
let var_exp, _ = match trans_state.var_exp_typ with Some e -> e | _ -> assert false in
let context = trans_state.context in
let succ_nodes = trans_state.succ_nodes in
@ -1529,7 +1521,6 @@ struct
let is_method_call = CTrans_utils.is_method_call stmt in
[(res_trans_stmt.ids, res_trans_stmt.instrs, exp, is_method_call, is_owning_method, typ)] in
let rec collect_left_hand_exprs e typ tns =
let open General_utils in
match typ with
| Sil.Tvar tn ->
(match Sil.tenv_lookup context.CContext.tenv tn with
@ -1563,7 +1554,7 @@ struct
let var_type = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in
let lh = IList.flatten (collect_left_hand_exprs var_exp var_type Utils.StringSet.empty) in
let rh = IList.flatten (IList.map (collect_right_hand_exprs trans_state_pri) stmts ) in
if (IList.length rh != IList.length lh) then (
if IList.length rh != IList.length lh then (
(* If the right hand expressions are not as many as the left hand expressions something's wrong *)
{ empty_res_trans with root_nodes = succ_nodes }
) else (
@ -1582,34 +1573,28 @@ struct
else
([], [Sil.Set (lh_exp, lh_t, rh_exp, sil_loc)], []))
(General_utils.zip lh rh) in
let rh_instrs = IList.flatten ( IList.map (fun (_, instrs, _, _, _, _) -> instrs) rh) in
let assign_instrs = IList.flatten(IList.map (fun (_, instrs, _) -> instrs) big_zip) in
let assign_ids = IList.flatten(IList.map (fun (_, _, ids) -> ids) big_zip) in
let instructions = IList.append (rh_instrs) assign_instrs in
let rh_ids = IList.flatten ( IList.map (fun (ids, _, _, _, _, _) -> ids) rh) in
let ids = IList.append (rh_ids) assign_ids in
let rh_instrs = IList.flatten (IList.map (fun (_, instrs, _, _, _, _) -> instrs) rh) in
let assign_instrs = IList.flatten (IList.map (fun (_, instrs, _) -> instrs) big_zip) in
let assign_ids = IList.flatten (IList.map (fun (_, _, ids) -> ids) big_zip) in
let instructions = IList.append rh_instrs assign_instrs in
let rh_ids = IList.flatten (IList.map (fun (ids, _, _, _, _, _) -> ids) rh) in
let ids = IList.append rh_ids assign_ids in
if PriorityNode.own_priority_node trans_state_pri.priority stmt_info then (
let node_kind = Cfg.Node.Stmt_node "InitListExp" in
let node = create_node node_kind (ids) (instructions) sil_loc context in
let node = create_node node_kind ids instructions sil_loc context in
Cfg.Node.set_succs_exn node succ_nodes [];
{
{ empty_res_trans with
root_nodes = [node];
leaf_nodes = [];
exps = [(var_exp, var_type)];
initd_exps = [var_exp];
ids = rh_ids;
instrs = instructions;
instrs = instructions; }
) else
{ empty_res_trans with
exps = [(var_exp, var_type)];
initd_exps = [var_exp];
is_cpp_call_virtual = false;
}
) else {
root_nodes = [];
leaf_nodes = [];
ids = rh_ids;
instrs = instructions;
exps = [(var_exp, var_type)];
initd_exps = [var_exp];
is_cpp_call_virtual = false;
}
ids = rh_ids;
instrs = instructions; }
)
and init_expr_trans trans_state var_exp_typ var_stmt_info init_expr_opt =
@ -1682,12 +1667,12 @@ struct
(* Var are defined when procdesc is created, here we only take care of initialization*)
let res_trans_vd = collect_all_decl trans_state var_decls' next_nodes stmt_info in
let res_trans_tmp = do_var_dec (di, n, tp, vdi) res_trans_vd.root_nodes in
{ root_nodes = res_trans_tmp.root_nodes; leaf_nodes = [];
{ empty_res_trans with
root_nodes = res_trans_tmp.root_nodes; leaf_nodes = [];
ids = res_trans_tmp.ids @ res_trans_vd.ids;
instrs = res_trans_tmp.instrs @ res_trans_vd.instrs;
exps = res_trans_tmp.exps @ res_trans_vd.exps;
initd_exps = res_trans_tmp.initd_exps @ res_trans_vd.initd_exps;
is_cpp_call_virtual = false;
}
| CXXRecordDecl _ :: var_decls' (*C++/C record decl treated in the same way *)
| RecordDecl _ :: var_decls' ->
@ -1763,10 +1748,12 @@ struct
let stmt = extract_stmt_from_singleton stmt_list
"WARNING: In CastExpr There must be only one stmt defining the expression to be cast.\n" in
let res_trans_stmt = instruction trans_state stmt in
let typ = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in
let typ =
CTypes_decl.type_ptr_to_sil_type context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in
let cast_kind = cast_expr_info.Clang_ast_t.cei_cast_kind in
(* This gives the differnece among cast operations kind*)
let cast_ids, cast_inst, cast_exp = cast_operation context cast_kind res_trans_stmt.exps typ sil_loc is_objc_bridged in
let cast_ids, cast_inst, cast_exp =
cast_operation context cast_kind res_trans_stmt.exps typ sil_loc is_objc_bridged in
{ res_trans_stmt with
ids = res_trans_stmt.ids @ cast_ids;
instrs = res_trans_stmt.instrs @ cast_inst;
@ -2019,13 +2006,17 @@ struct
{ res_trans with exps = [var_exp_typ] }
and compoundLiteralExpr_trans trans_state stmt_list expr_info =
let context = trans_state.context in
let procdesc = context.CContext.procdesc in
let (pvar, typ) = mk_temp_sil_var_for_expr context.CContext.tenv procdesc
"SIL_compound_literal__" expr_info in
Cfg.Procdesc.append_locals procdesc [(Sil.pvar_get_name pvar, typ)];
let trans_state' = { trans_state with var_exp_typ = Some (Sil.Lvar pvar, typ) } in
let stmt = match stmt_list with [stmt] -> stmt | _ -> assert false in
let var_exp_typ =
if Option.is_some trans_state.var_exp_typ then trans_state.var_exp_typ
else
let context = trans_state.context in
let procdesc = context.CContext.procdesc in
let (pvar, typ) = mk_temp_sil_var_for_expr context.CContext.tenv procdesc
"SIL_compound_literal__" expr_info in
Cfg.Procdesc.append_locals procdesc [(Sil.pvar_get_name pvar, typ)];
Some (Sil.Lvar pvar, typ) in
let trans_state' = { trans_state with var_exp_typ = var_exp_typ } in
instruction trans_state' stmt
and cxxDynamicCastExpr_trans trans_state stmt_info stmts cast_type_ptr =
@ -2351,13 +2342,13 @@ struct
then { trans_state with succ_nodes = res_trans_s.root_nodes }
else trans_state in
let res_trans_tail = exec_trans_instrs_no_rev trans_state' trans_stmt_fun_list' in
{ root_nodes = res_trans_tail.root_nodes;
{ empty_res_trans with
root_nodes = res_trans_tail.root_nodes;
leaf_nodes = [];
ids = res_trans_s.ids @ res_trans_tail.ids;
instrs = res_trans_tail.instrs @ res_trans_s.instrs;
exps = res_trans_tail.exps @ res_trans_s.exps;
initd_exps = res_trans_tail.initd_exps @ res_trans_s.initd_exps;
is_cpp_call_virtual = false
} in
exec_trans_instrs_no_rev trans_state (IList.rev trans_stmt_fun_list)

@ -146,7 +146,7 @@ type trans_result = {
instrs: Sil.instr list; (* list of SIL instruction that need to be placed in cfg nodes of the parent*)
exps: (Sil.exp * Sil.typ) list; (* SIL expressions resulting from the translation of the clang stmt *)
initd_exps: Sil.exp list;
is_cpp_call_virtual : bool
is_cpp_call_virtual : bool;
}
(* Empty result translation *)
@ -181,7 +181,7 @@ let collect_res_trans l =
instrs = rt.instrs@rt'.instrs;
exps = rt.exps@rt'.exps;
initd_exps = rt.initd_exps@rt'.initd_exps;
is_cpp_call_virtual = false} in
is_cpp_call_virtual = false; } in
collect l empty_res_trans
(* priority_node is used to enforce some kind of policy for creating nodes *)

@ -16,5 +16,5 @@ int compound_literal_expr() { return ((struct point){.y = 32, .x = 52}).x; }
int init_with_compound_literal() {
struct point p = (struct point){32, 52};
return p.x;
return 1 / (p.x - 32);
}

@ -1,16 +1,16 @@
digraph iCFG {
7 [label="7: DeclStmt \n *&SIL_compound_literal__n$1.x:int =32 [line 18]\n *&SIL_compound_literal__n$1.y:int =52 [line 18]\n n$2=*&SIL_compound_literal__n$1:struct point [line 18]\n *&p:struct point =n$2 [line 18]\n REMOVE_TEMPS(n$2); [line 18]\n NULLIFY(&SIL_compound_literal__n$1,false); [line 18]\n " shape="box"]
7 [label="7: DeclStmt \n *&p.x:int =32 [line 18]\n *&p.y:int =52 [line 18]\n n$1=*&p:struct point [line 18]\n REMOVE_TEMPS(n$1); [line 18]\n " shape="box"]
7 -> 6 ;
6 [label="6: Return Stmt \n n$0=*&p.x:int [line 19]\n *&return:int =n$0 [line 19]\n REMOVE_TEMPS(n$0); [line 19]\n NULLIFY(&p,false); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"]
6 [label="6: Return Stmt \n n$0=*&p.x:int [line 19]\n *&return:int =(1 / (n$0 - 32)) [line 19]\n REMOVE_TEMPS(n$0); [line 19]\n NULLIFY(&p,false); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"]
6 -> 5 ;
5 [label="5: Exit init_with_compound_literal \n " color=yellow style=filled]
4 [label="4: Start init_with_compound_literal\nFormals: \nLocals: p:struct point SIL_compound_literal__n$1:struct point \n DECLARE_LOCALS(&return,&p,&SIL_compound_literal__n$1); [line 17]\n NULLIFY(&p,false); [line 17]\n " color=yellow style=filled]
4 [label="4: Start init_with_compound_literal\nFormals: \nLocals: p:struct point \n DECLARE_LOCALS(&return,&p); [line 17]\n " color=yellow style=filled]
4 -> 7 ;

@ -16,9 +16,9 @@ int foo() { return 5; }
int main() { struct Point p = {1, foo() + 3}; }
int test(Point* p) {
int point_coords_set_correctly(Point* p) {
*p = (Point){4, 5};
return 0;
return 1 / (p->x - 4);
}
struct Employee {

@ -14,18 +14,18 @@ digraph iCFG {
11 -> 14 ;
10 [label="10: InitListExp \n *&p.x:int =4 [line 20]\n *&p.y:int =5 [line 20]\n " shape="box"]
10 [label="10: BinaryOperatorStmt: Assign \n n$2=*&p:struct Point * [line 20]\n *n$2.x:int =4 [line 20]\n *n$2.y:int =5 [line 20]\n n$3=*n$2:struct Point [line 20]\n REMOVE_TEMPS(n$2,n$3); [line 20]\n " shape="box"]
10 -> 9 ;
9 [label="9: Return Stmt \n *&return:int =0 [line 21]\n APPLY_ABSTRACTION; [line 21]\n " shape="box"]
9 [label="9: Return Stmt \n n$0=*&p:struct Point * [line 21]\n n$1=*n$0.x:int [line 21]\n *&return:int =(1 / (n$1 - 4)) [line 21]\n REMOVE_TEMPS(n$0,n$1); [line 21]\n NULLIFY(&p,false); [line 21]\n APPLY_ABSTRACTION; [line 21]\n " shape="box"]
9 -> 8 ;
8 [label="8: Exit test \n " color=yellow style=filled]
8 [label="8: Exit point_coords_set_correctly \n " color=yellow style=filled]
7 [label="7: Start test\nFormals: p:struct Point *\nLocals: \n DECLARE_LOCALS(&return); [line 19]\n NULLIFY(&p,false); [line 19]\n " color=yellow style=filled]
7 [label="7: Start point_coords_set_correctly\nFormals: p:struct Point *\nLocals: \n DECLARE_LOCALS(&return); [line 19]\n " color=yellow style=filled]
7 -> 10 ;

@ -0,0 +1,64 @@
/*
* Copyright (c) 2013 - 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.objc;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsErrorInMethod.contains;
import static utils.matchers.ResultContainsExactly.containsExactly;
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 CompoundLiteralExprTest {
public static final String FILE =
"infer/tests/codetoanalyze/c/frontend/initialization/compound_literal.c";
public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO";
private static ImmutableList<String> inferCmd;
@ClassRule
public static DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferCmd = InferRunner.createCInferCommand(folder, FILE);
}
@Test
public void compoundLiteralExprTest() throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferC(inferCmd);
String[] procedures = {
"init_with_compound_literal",
};
assertThat(
"Results should contain divide by zero",
inferResults,
containsExactly(
DIVIDE_BY_ZERO,
FILE,
procedures
)
);
}
}

@ -0,0 +1,64 @@
/*
* Copyright (c) 2013 - 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.objc;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsErrorInMethod.contains;
import static utils.matchers.ResultContainsExactly.containsExactly;
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 InitListExprTest {
public static final String FILE =
"infer/tests/codetoanalyze/c/frontend/initialization/struct_initlistexpr.c";
public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO";
private static ImmutableList<String> inferCmd;
@ClassRule
public static DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferCmd = InferRunner.createiOSInferCommandWithMLBuckets(folder, FILE, "cf", true);
}
@Test
public void nullDereferenceTest() throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferC(inferCmd);
String[] procedures = {
"point_coords_set_correctly",
};
assertThat(
"Results should contain divide by zero",
inferResults,
containsExactly(
DIVIDE_BY_ZERO,
FILE,
procedures
)
);
}
}
Loading…
Cancel
Save