diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index daa8e6224..26d5f5f1c 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -2413,19 +2413,28 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s in stmt_res_trans :: rest_stmts_res_trans - and lambdaExpr_trans trans_state expr_info decl = + and lambdaExpr_trans trans_state expr_info {Clang_ast_t.lei_lambda_decl; lei_captures} = let open CContext in let qual_type = expr_info.Clang_ast_t.ei_qual_type in let context = trans_state.context in - call_translation context decl ; + call_translation context lei_lambda_decl ; let procname = Procdesc.get_proc_name context.procdesc in - let lambda_pname = CMethod_trans.get_procname_from_cpp_lambda context decl in + let lambda_pname = CMethod_trans.get_procname_from_cpp_lambda context lei_lambda_decl in let typ = CType_decl.qual_type_to_sil_type context.tenv qual_type in (* We need to set the explicit dependency between the newly created lambda and the *) (* defining procedure. We add an edge in the call graph.*) Cg.add_edge context.cg procname lambda_pname ; - let captured_vars = [] in - (* TODO *) + let captured_vars = + List.fold_right + ~f:(fun {Clang_ast_t.lci_captured_var} acc -> + match lci_captured_var with + | Some decl_ref + -> CVar_decl.sil_var_of_captured_var decl_ref context procname :: acc + | None + -> acc) + ~init:[] lei_captures + |> List.map ~f:(fun (pvar, typ) -> (Exp.Lvar pvar, pvar, typ)) + in let closure = Exp.Closure {name= lambda_pname; captured_vars} in {empty_res_trans with exps= [(closure, typ)]} @@ -2927,8 +2936,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s -> cxxStdInitializerListExpr_trans trans_state stmt_info stmts expr_info | LambdaExpr (_, _, expr_info, lambda_expr_info) -> let trans_state' = {trans_state with priority= Free} in - let decl = lambda_expr_info.Clang_ast_t.lei_lambda_decl in - lambdaExpr_trans trans_state' expr_info decl + lambdaExpr_trans trans_state' expr_info lambda_expr_info | AttributedStmt (_, stmts, attrs) -> attributedStmt_trans trans_state stmts attrs | TypeTraitExpr (_, _, expr_info, type_trait_info) diff --git a/infer/src/clang/cVar_decl.ml b/infer/src/clang/cVar_decl.ml index 307a5e097..571b61dd7 100644 --- a/infer/src/clang/cVar_decl.ml +++ b/infer/src/clang/cVar_decl.ml @@ -89,23 +89,23 @@ let compute_autorelease_pool_vars context stmts = in Exp.Map.bindings (do_stmts Exp.Map.empty stmts) +let sil_var_of_captured_var decl_ref context procname = + match decl_ref with + | {Clang_ast_t.dr_qual_type= Some qual_type} + -> ( sil_var_of_decl_ref context decl_ref procname + , CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type ) + | _ + -> assert false + (* Returns a list of captured variables as sil variables. *) let captured_vars_from_block_info context cvl = let procname = Procdesc.get_proc_name context.CContext.procdesc in - let sil_var_of_captured_var cv vars = - match cv.Clang_ast_t.bcv_variable with - | Some dr -> ( - match (dr.Clang_ast_t.dr_name, dr.Clang_ast_t.dr_qual_type) with - | Some name_info, Some qual_type - -> let n = name_info.Clang_ast_t.ni_name in - if String.equal n CFrontend_config.self && not (CContext.is_objc_instance context) then - vars - else - let pvar = sil_var_of_decl_ref context dr procname in - let typ = CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type in - (pvar, typ) :: vars - | _ - -> assert false ) + let sil_var_of_captured_var {Clang_ast_t.bcv_variable} vars_acc = + match bcv_variable with + | Some ({Clang_ast_t.dr_name= Some {Clang_ast_t.ni_name}} as decl_ref) + -> if String.equal ni_name CFrontend_config.self && not (CContext.is_objc_instance context) + then vars_acc + else sil_var_of_captured_var decl_ref context procname :: vars_acc | _ -> assert false in diff --git a/infer/src/clang/cVar_decl.mli b/infer/src/clang/cVar_decl.mli index 5d37ee76b..25ebb8e06 100644 --- a/infer/src/clang/cVar_decl.mli +++ b/infer/src/clang/cVar_decl.mli @@ -21,5 +21,8 @@ val add_var_to_locals : Procdesc.t -> Clang_ast_t.decl -> Typ.t -> Pvar.t -> uni val compute_autorelease_pool_vars : CContext.t -> Clang_ast_t.stmt list -> (Exp.t * Typ.t) list +val sil_var_of_captured_var : + Clang_ast_t.decl_ref -> CContext.t -> Typ.Procname.t -> Pvar.t * Typ.typ + val captured_vars_from_block_info : CContext.t -> Clang_ast_t.block_captured_variable list -> (Pvar.t * Typ.t) list diff --git a/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp b/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp index 34a0552b8..7c9ee8a3b 100644 --- a/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp +++ b/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp @@ -46,6 +46,15 @@ int plus_plus3_bad() { return i++; } +void FN_capture_no_read_bad() { + int x = 0; + [x]() { return; }(); +} + +void FN_init_capture_no_read_bad() { + [i = 0]() { return; }; +} + int return_ok() { int x = 5; return x; @@ -98,7 +107,9 @@ int* assign_pointer2_ok() { return ptr; } -void by_ref_ok(int& ref) { ref = 7; } +void by_ref1_ok(int& ref) { ref = 7; } + +void by_ref2_ok(int& ref) { ref++; } int plus_plus_ok() { int x = 0; @@ -113,6 +124,25 @@ int plus_plus_loop_ok(int n) { return i; } +void capture1_ok() { + int x = 1; + [x]() { return x; }(); +} + +void capture2_ok(int x) { + [x]() { return x; }(); +} + +int FP_capture_by_ref_ok() { + int x = 0; + [&x]() { x++; }(); + return x; +} + +void init_capture_ok() { + [i = 0]() { return i; }; +} + char* global; void FP_assign_array_tricky_ok() { diff --git a/infer/tests/codetoanalyze/cpp/liveness/issues.exp b/infer/tests/codetoanalyze/cpp/liveness/issues.exp index d3e683524..b88fe2923 100644 --- a/infer/tests/codetoanalyze/cpp/liveness/issues.exp +++ b/infer/tests/codetoanalyze/cpp/liveness/issues.exp @@ -1,4 +1,5 @@ codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::FP_assign_array_tricky_ok, 3, DEAD_STORE, [Write of unused value] +codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::FP_capture_by_ref_ok::lambda_dead_stores.cpp:138:3_operator(), 0, DEAD_STORE, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::dead_pointer_bad, 2, DEAD_STORE, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::dead_then_live_bad, 1, DEAD_STORE, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::easy_bad, 0, DEAD_STORE, [Write of unused value] diff --git a/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp b/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp index 64e8f421d..042ec458a 100644 --- a/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp +++ b/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp @@ -27,6 +27,18 @@ int fooOK() { return 5 / (4 - y(3)); } +int normal_capture() { + int x = 1; + int y = 2; + return [x, y]() { return x + y; }(); +} + +int capture_by_ref() { + int x = 0; + [&x]() { x++; }(); + return x; +} + void init_capture() { [i = 0]() { i; }; } diff --git a/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot b/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot index 5166187c8..5b940b887 100644 --- a/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot +++ b/infer/tests/codetoanalyze/cpp/shared/lambda/lambda1.cpp.dot @@ -49,7 +49,45 @@ digraph iCFG { "fooOK#_Z5fooOKv.17fb07f2bfe616303a58d2e25ed98781_4" -> "fooOK#_Z5fooOKv.17fb07f2bfe616303a58d2e25ed98781_3" ; -"init_capture#_Z12init_capturev.b56a308a8fe2b749cb39e3b566237ec2_1" [label="1: Start init_capture\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 30]\n " color=yellow style=filled] +"normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_1" [label="1: Start normal_capture\nFormals: \nLocals: y:int x:int \n DECLARE_LOCALS(&return,&y,&x); [line 30]\n " color=yellow style=filled] + + + "normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_1" -> "normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_5" ; +"normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_2" [label="2: Exit normal_capture \n " color=yellow style=filled] + + +"normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_3" [label="3: Return Stmt \n n$0=_fun_normal_capture::lambda_shared_lambda_lambda1.cpp:33:10_operator()((_fun_normal_capture::lambda_shared_lambda_lambda1.cpp:33:10_operator(),&x,&y):normal_capture::lambda_shared_lambda_lambda1.cpp:33:10) [line 33]\n *&return:int=n$0 [line 33]\n " shape="box"] + + + "normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_3" -> "normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_2" ; +"normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_4" [label="4: DeclStmt \n *&y:int=2 [line 32]\n " shape="box"] + + + "normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_4" -> "normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_3" ; +"normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_5" [label="5: DeclStmt \n *&x:int=1 [line 31]\n " shape="box"] + + + "normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_5" -> "normal_capture#_Z14normal_capturev.9af9b723c040290ea713f2d1bc6c66e2_4" ; +"capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_1" [label="1: Start capture_by_ref\nFormals: \nLocals: x:int \n DECLARE_LOCALS(&return,&x); [line 36]\n " color=yellow style=filled] + + + "capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_1" -> "capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_5" ; +"capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_2" [label="2: Exit capture_by_ref \n " color=yellow style=filled] + + +"capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_3" [label="3: Return Stmt \n n$0=*&x:int [line 39]\n *&return:int=n$0 [line 39]\n " shape="box"] + + + "capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_3" -> "capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_2" ; +"capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_4" [label="4: Call _fun_capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator() \n _fun_capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator()((_fun_capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator(),&x):capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3) [line 38]\n " shape="box"] + + + "capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_4" -> "capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_3" ; +"capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_5" [label="5: DeclStmt \n *&x:int=0 [line 37]\n " shape="box"] + + + "capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_5" -> "capture_by_ref#_Z14capture_by_refv.c683a8db53a834aa19283088dfffe460_4" ; +"init_capture#_Z12init_capturev.b56a308a8fe2b749cb39e3b566237ec2_1" [label="1: Start init_capture\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 42]\n " color=yellow style=filled] "init_capture#_Z12init_capturev.b56a308a8fe2b749cb39e3b566237ec2_1" -> "init_capture#_Z12init_capturev.b56a308a8fe2b749cb39e3b566237ec2_2" ; @@ -132,11 +170,33 @@ digraph iCFG { "operator()#lambda_shared_lambda_lambda1.cpp:26:12#fooOK#(_ZZ5fooOKvENK3$_3clEi).3d555a16319a7bb49d565b6ed9aa8c7f_3" -> "operator()#lambda_shared_lambda_lambda1.cpp:26:12#fooOK#(_ZZ5fooOKvENK3$_3clEi).3d555a16319a7bb49d565b6ed9aa8c7f_2" ; -"operator()#lambda_shared_lambda_lambda1.cpp:31:3#init_capture#(_ZZ12init_capturevENK3$_4clEv).1a4cfb9f400c66ee04ea1f7aeeef1d92_1" [label="1: Start init_capture::lambda_shared_lambda_lambda1.cpp:31:3_operator()\nFormals: this:init_capture::lambda_shared_lambda_lambda1.cpp:31:3*\nLocals: \n DECLARE_LOCALS(&return); [line 31]\n " color=yellow style=filled] +"operator()#lambda_shared_lambda_lambda1.cpp:33:10#normal_capture#(_ZZ14normal_capturevENK3$_4clEv).d3f05aea738c7b3e4662812f831b95f4_1" [label="1: Start normal_capture::lambda_shared_lambda_lambda1.cpp:33:10_operator()\nFormals: this:normal_capture::lambda_shared_lambda_lambda1.cpp:33:10*\nLocals: \n DECLARE_LOCALS(&return); [line 33]\n " color=yellow style=filled] + + + "operator()#lambda_shared_lambda_lambda1.cpp:33:10#normal_capture#(_ZZ14normal_capturevENK3$_4clEv).d3f05aea738c7b3e4662812f831b95f4_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:33:10#normal_capture#(_ZZ14normal_capturevENK3$_4clEv).d3f05aea738c7b3e4662812f831b95f4_3" ; +"operator()#lambda_shared_lambda_lambda1.cpp:33:10#normal_capture#(_ZZ14normal_capturevENK3$_4clEv).d3f05aea738c7b3e4662812f831b95f4_2" [label="2: Exit normal_capture::lambda_shared_lambda_lambda1.cpp:33:10_operator() \n " color=yellow style=filled] + + +"operator()#lambda_shared_lambda_lambda1.cpp:33:10#normal_capture#(_ZZ14normal_capturevENK3$_4clEv).d3f05aea738c7b3e4662812f831b95f4_3" [label="3: Return Stmt \n n$0=*&x:int [line 33]\n n$1=*&y:int [line 33]\n *&return:int=(n$0 + n$1) [line 33]\n " shape="box"] + + + "operator()#lambda_shared_lambda_lambda1.cpp:33:10#normal_capture#(_ZZ14normal_capturevENK3$_4clEv).d3f05aea738c7b3e4662812f831b95f4_3" -> "operator()#lambda_shared_lambda_lambda1.cpp:33:10#normal_capture#(_ZZ14normal_capturevENK3$_4clEv).d3f05aea738c7b3e4662812f831b95f4_2" ; +"operator()#lambda_shared_lambda_lambda1.cpp:38:3#capture_by_ref#(_ZZ14capture_by_refvENK3$_5clEv).801ff4a46ab35f8d28f7ad0e26ae456e_1" [label="1: Start capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator()\nFormals: this:capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3*\nLocals: \n DECLARE_LOCALS(&return); [line 38]\n " color=yellow style=filled] + + + "operator()#lambda_shared_lambda_lambda1.cpp:38:3#capture_by_ref#(_ZZ14capture_by_refvENK3$_5clEv).801ff4a46ab35f8d28f7ad0e26ae456e_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:38:3#capture_by_ref#(_ZZ14capture_by_refvENK3$_5clEv).801ff4a46ab35f8d28f7ad0e26ae456e_3" ; +"operator()#lambda_shared_lambda_lambda1.cpp:38:3#capture_by_ref#(_ZZ14capture_by_refvENK3$_5clEv).801ff4a46ab35f8d28f7ad0e26ae456e_2" [label="2: Exit capture_by_ref::lambda_shared_lambda_lambda1.cpp:38:3_operator() \n " color=yellow style=filled] + + +"operator()#lambda_shared_lambda_lambda1.cpp:38:3#capture_by_ref#(_ZZ14capture_by_refvENK3$_5clEv).801ff4a46ab35f8d28f7ad0e26ae456e_3" [label="3: UnaryOperator \n n$0=*&x:int [line 38]\n *&x:int=(n$0 + 1) [line 38]\n " shape="box"] + + + "operator()#lambda_shared_lambda_lambda1.cpp:38:3#capture_by_ref#(_ZZ14capture_by_refvENK3$_5clEv).801ff4a46ab35f8d28f7ad0e26ae456e_3" -> "operator()#lambda_shared_lambda_lambda1.cpp:38:3#capture_by_ref#(_ZZ14capture_by_refvENK3$_5clEv).801ff4a46ab35f8d28f7ad0e26ae456e_2" ; +"operator()#lambda_shared_lambda_lambda1.cpp:43:3#init_capture#(_ZZ12init_capturevENK3$_6clEv).43d5b008ae982e3438cddd48c4a55f04_1" [label="1: Start init_capture::lambda_shared_lambda_lambda1.cpp:43:3_operator()\nFormals: this:init_capture::lambda_shared_lambda_lambda1.cpp:43:3*\nLocals: \n DECLARE_LOCALS(&return); [line 43]\n " color=yellow style=filled] - "operator()#lambda_shared_lambda_lambda1.cpp:31:3#init_capture#(_ZZ12init_capturevENK3$_4clEv).1a4cfb9f400c66ee04ea1f7aeeef1d92_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:31:3#init_capture#(_ZZ12init_capturevENK3$_4clEv).1a4cfb9f400c66ee04ea1f7aeeef1d92_2" ; -"operator()#lambda_shared_lambda_lambda1.cpp:31:3#init_capture#(_ZZ12init_capturevENK3$_4clEv).1a4cfb9f400c66ee04ea1f7aeeef1d92_2" [label="2: Exit init_capture::lambda_shared_lambda_lambda1.cpp:31:3_operator() \n " color=yellow style=filled] + "operator()#lambda_shared_lambda_lambda1.cpp:43:3#init_capture#(_ZZ12init_capturevENK3$_6clEv).43d5b008ae982e3438cddd48c4a55f04_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:43:3#init_capture#(_ZZ12init_capturevENK3$_6clEv).43d5b008ae982e3438cddd48c4a55f04_2" ; +"operator()#lambda_shared_lambda_lambda1.cpp:43:3#init_capture#(_ZZ12init_capturevENK3$_6clEv).43d5b008ae982e3438cddd48c4a55f04_2" [label="2: Exit init_capture::lambda_shared_lambda_lambda1.cpp:43:3_operator() \n " color=yellow style=filled] }