diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index de302d308..332133aef 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -224,6 +224,15 @@ struct f trans_state e else f { trans_state with priority = Free } e + let mk_temp_sil_var_for_expr tenv procdesc var_name_prefix expr_info = + let procname = Cfg.Procdesc.get_proc_name procdesc in + let id = Ident.create_fresh Ident.knormal in + let pvar_mangled = Mangled.from_string (var_name_prefix ^ Ident.to_string id) in + let pvar = Sil.mk_pvar pvar_mangled procname in + let type_ptr = expr_info.Clang_ast_t.ei_type_ptr in + let typ = CTypes_decl.type_ptr_to_sil_type tenv type_ptr in + (pvar, typ) + let breakStmt_trans trans_state = match trans_state.continuation with | Some bn -> { empty_res_trans with root_nodes = bn.break } @@ -1447,6 +1456,7 @@ struct | _ -> Printing.log_stats "\n!!!!WARNING: found statement <\"ImplicitValueInitExpr\"> with non-empty stmt_list.\n"); { empty_res_trans with root_nodes = trans_state.succ_nodes } | Some (InitListExpr (stmt_info , stmts , expr_info)) + | Some (ImplicitCastExpr (_, [CompoundLiteralExpr (_, [InitListExpr (stmt_info , stmts , expr_info)], _)], _, _)) | Some (ExprWithCleanups (_, [InitListExpr (stmt_info , stmts , expr_info)], _, _)) -> initListExpr_trans trans_state var_res_trans stmt_info expr_info stmts | Some (CXXConstructExpr _ as expr) -> @@ -1809,20 +1819,24 @@ struct and materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info = let context = trans_state.context in let procdesc = context.CContext.procdesc in - let procname = Cfg.Procdesc.get_proc_name procdesc in - let temp_exp = match stmt_list with [p] -> p | _ -> assert false in - (* use id to create unique variable name within a function *) - let id = Ident.create_fresh Ident.knormal in - let pvar_mangled = Mangled.from_string ("SIL_materialize_temp__" ^ (Ident.to_string id)) in - let pvar = Sil.mk_pvar pvar_mangled procname in - let type_ptr = expr_info.Clang_ast_t.ei_type_ptr in - let typ = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv type_ptr in + let (pvar, typ) = mk_temp_sil_var_for_expr context.CContext.tenv procdesc + "SIL_materialize_temp__" expr_info in let typ_ptr = Sil.Tptr (typ, Sil.Pk_pointer) in let var_res_trans = { empty_res_trans with exps = [(Sil.Lvar pvar, typ_ptr)] } in + let temp_exp = match stmt_list with [p] -> p | _ -> assert false in Cfg.Procdesc.append_locals procdesc [(Sil.pvar_get_name pvar, typ)]; let res_trans = init_expr_trans trans_state var_res_trans stmt_info (Some temp_exp) in { res_trans with exps = [(Sil.Lvar pvar, typ)] } + and compoundLiteralExpr_trans trans_state stmt_info 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 + let typ_ptr = Sil.Tptr (typ, Sil.Pk_pointer) in + let var_res_trans = { empty_res_trans with exps = [(Sil.Lvar pvar, typ_ptr)] } in + initListExpr_trans trans_state var_res_trans stmt_info expr_info stmt_list + (* Translates a clang instruction into SIL instructions. It takes a *) (* a trans_state containing current info on the translation and it returns *) (* a result_state.*) @@ -2038,6 +2052,8 @@ struct cxxDeleteExpr_trans trans_state stmt_info stmt_list expr_info delete_expr_info | MaterializeTemporaryExpr (stmt_info, stmt_list, expr_info, _) -> materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info + | CompoundLiteralExpr (_, [InitListExpr (stmt_info , stmt_list , expr_info)], _) -> + compoundLiteralExpr_trans trans_state stmt_info stmt_list expr_info | s -> (Printing.log_stats "\n!!!!WARNING: found statement %s. \nACTION REQUIRED: Translation need to be defined. Statement ignored.... \n" (Ast_utils.string_of_stmt s); diff --git a/infer/tests/codetoanalyze/c/frontend/initialization/compound_literal.c b/infer/tests/codetoanalyze/c/frontend/initialization/compound_literal.c new file mode 100644 index 000000000..e42f1990f --- /dev/null +++ b/infer/tests/codetoanalyze/c/frontend/initialization/compound_literal.c @@ -0,0 +1,22 @@ +/* + * 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. + */ + +struct point { + int x; + int y; +}; + +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; +} diff --git a/infer/tests/codetoanalyze/c/frontend/initialization/compound_literal.c.dot b/infer/tests/codetoanalyze/c/frontend/initialization/compound_literal.c.dot new file mode 100644 index 000000000..faa7080ee --- /dev/null +++ b/infer/tests/codetoanalyze/c/frontend/initialization/compound_literal.c.dot @@ -0,0 +1,28 @@ +digraph iCFG { +7 [label="7: InitListExp \n *&p.x:int =32 [line 20]\n *&p.y:int =52 [line 20]\n " shape="box"] + + + 7 -> 6 ; +6 [label="6: Return Stmt \n n$0=*&p.x:int [line 21]\n *&return:int =n$0 [line 21]\n REMOVE_TEMPS(n$0); [line 21]\n NULLIFY(&p,false); [line 21]\n APPLY_ABSTRACTION; [line 21]\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 \n DECLARE_LOCALS(&return,&p); [line 19]\n " color=yellow style=filled] + + + 4 -> 7 ; +3 [label="3: Return Stmt \n *&SIL_compound_literal__n$0.x:int =52 [line 16]\n *&SIL_compound_literal__n$0.y:int =32 [line 16]\n n$1=*&SIL_compound_literal__n$0.x:int [line 16]\n *&return:int =n$1 [line 16]\n REMOVE_TEMPS(n$1); [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit compound_literal_expr \n " color=yellow style=filled] + + +1 [label="1: Start compound_literal_expr\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 15]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/frontend/c/InitListExprTest.java b/infer/tests/frontend/c/InitListExprTest.java index 2ce082681..1a7b0c0af 100644 --- a/infer/tests/frontend/c/InitListExprTest.java +++ b/infer/tests/frontend/c/InitListExprTest.java @@ -40,4 +40,11 @@ public class InitListExprTest { throws InterruptedException, IOException, InferException { frontendTest("struct_initlistexpr.c"); } + + @Test + public void whenCaptureRunOnCompoundLiteralExprThenDotFilesAreTheSame() + throws InterruptedException, IOException, InferException { + frontendTest("compound_literal.c"); + } + }