[clang][dead stores] translate init-capture expressions

Summary:
Not translating these properly was causing false positives for the dead store analysis in cases like

```
int i = 0;
return [j = i]() { return j; }();
```

Reviewed By: da319

Differential Revision: D5731562

fbshipit-source-id: ae79ac8
master
Sam Blackshear 7 years ago committed by Facebook Github Bot
parent 9ab89025a8
commit 14fa4aa7d9

@ -2587,7 +2587,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
| _
-> assert false
and lambdaExpr_trans trans_state expr_info {Clang_ast_t.lei_lambda_decl; lei_captures} =
and lambdaExpr_trans trans_state stmt_info 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
@ -2598,19 +2598,40 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
(* 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 =
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 make_captured_tuple (pvar, typ) = (Exp.Lvar pvar, pvar, typ) in
let get_captured_pvar_typ decl_ref =
CVar_decl.sil_var_of_captured_var decl_ref context procname
in
let translate_capture_init (pvar, typ) init_decl =
match init_decl with
| Clang_ast_t.VarDecl (_, _, _, {vdi_init_expr})
-> init_expr_trans trans_state (Exp.Lvar pvar, typ) stmt_info vdi_init_expr
| _
-> L.die ExternalError "Unexpected: capture-init statement without var decl"
in
let translate_captured {Clang_ast_t.lci_captured_var; lci_init_captured_vardecl}
(trans_results_acc, captured_vars_acc as acc) =
match (lci_captured_var, lci_init_captured_vardecl) with
| Some captured_var_decl_ref, Some init_decl
-> (* capture and init *)
let pvar_typ = get_captured_pvar_typ captured_var_decl_ref in
( translate_capture_init pvar_typ init_decl :: trans_results_acc
, make_captured_tuple pvar_typ :: captured_vars_acc )
| Some captured_var_decl_ref, None
-> (* just capture *)
let pvar_typ = get_captured_pvar_typ captured_var_decl_ref in
(trans_results_acc, make_captured_tuple pvar_typ :: captured_vars_acc)
| None, None
-> acc
| None, Some _
-> L.die InternalError "Capture-init with init, but no capture"
in
let trans_results, captured_vars =
List.fold_right ~f:translate_captured ~init:([], []) lei_captures
in
let final_trans_result = collect_res_trans context.procdesc trans_results in
let closure = Exp.Closure {name= lambda_pname; captured_vars} in
{empty_res_trans with exps= [(closure, typ)]}
{final_trans_result with exps= [(closure, typ)]}
and cxxNewExpr_trans trans_state stmt_info expr_info cxx_new_expr_info =
let context = trans_state.context in
@ -3116,9 +3137,9 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
-> cxxTypeidExpr_trans trans_state stmt_info stmts expr_info
| CXXStdInitializerListExpr (stmt_info, stmts, expr_info)
-> cxxStdInitializerListExpr_trans trans_state stmt_info stmts expr_info
| LambdaExpr (_, _, expr_info, lambda_expr_info)
| LambdaExpr (stmt_info, _, expr_info, lambda_expr_info)
-> let trans_state' = {trans_state with priority= Free} in
lambdaExpr_trans trans_state' expr_info lambda_expr_info
lambdaExpr_trans trans_state' stmt_info expr_info lambda_expr_info
| AttributedStmt (_, stmts, attrs)
-> attributedStmt_trans trans_state stmts attrs
| TypeTraitExpr (_, _, expr_info, type_trait_info)

@ -171,7 +171,7 @@ codetoanalyze/cpp/errors/smart_ptr/weak_ptr.cpp, weak_ptr_observers::lock_can_be
codetoanalyze/cpp/errors/smart_ptr/weak_ptr.cpp, weak_ptr_observers::shared_still_in_scope_good_FP, 6, NULL_DEREFERENCE, [start of procedure weak_ptr_observers::shared_still_in_scope_good_FP()]
codetoanalyze/cpp/errors/smart_ptr/weak_ptr.cpp, weak_ptr_observers::use_count_after_reset_bad, 5, use_count after weak_ptr reset is 0, [start of procedure weak_ptr_observers::use_count_after_reset_bad(),Condition is true,return from a call to weak_ptr_observers::use_count_after_reset_bad]
codetoanalyze/cpp/errors/smart_ptr/weak_ptr.cpp, weak_ptr_observers::use_count_empty_bad, 5, use_count on empty weak_ptr is 0, [start of procedure weak_ptr_observers::use_count_empty_bad(),Condition is true,return from a call to weak_ptr_observers::use_count_empty_bad]
codetoanalyze/cpp/errors/smart_ptr/weak_ptr_compil.cpp, weak_ptr_lock_repro_large::RDC::create::lambda_smart_ptr_weak_ptr_compil.cpp:62:7_operator(), 2, Cannot_star, [start of procedure operator(),Condition is true]
codetoanalyze/cpp/errors/smart_ptr/weak_ptr_compil.cpp, weak_ptr_lock_repro_large::RDC::create::lambda_smart_ptr_weak_ptr_compil.cpp:62:7_operator(), 2, Cannot_star, [start of procedure operator(),Condition is true,Skipping function: function or method not found]
codetoanalyze/cpp/errors/stack_escape/basic.cpp, B_return_ref, 0, STACK_VARIABLE_ADDRESS_ESCAPE, [start of procedure return_ref,start of procedure A,return from a call to A_A,return from a call to B_return_ref]
codetoanalyze/cpp/errors/stack_escape/basic.cpp, basic_escape_local_bad, 3, STACK_VARIABLE_ADDRESS_ESCAPE, [start of procedure basic_escape_local_bad(),return from a call to basic_escape_local_bad]
codetoanalyze/cpp/errors/stack_escape/basic.cpp, basic_escape_param_bad, 0, STACK_VARIABLE_ADDRESS_ESCAPE, [start of procedure basic_escape_param_bad(),return from a call to basic_escape_param_bad]

@ -9,7 +9,7 @@ TESTS_DIR = ../../..
ANALYZER = checkers
# see explanations in cpp/errors/Makefile for the custom isystem
CLANG_OPTIONS = -x c++ -std=c++11 -nostdinc++ -isystem$(MODELS_DIR)/cpp/include -isystem$(CLANG_INCLUDES)/c++/v1/ -c
CLANG_OPTIONS = -x c++ -std=c++14 -nostdinc++ -isystem$(MODELS_DIR)/cpp/include -isystem$(CLANG_INCLUDES)/c++/v1/ -c
INFER_OPTIONS = --liveness --ml-buckets cpp --debug-exceptions --project-root $(TESTS_DIR) --no-keep-going
INFERPRINT_OPTIONS = --issues-tests

@ -51,8 +51,19 @@ void FN_capture_no_read_bad() {
[x]() { return; }();
}
void FN_init_capture_no_read_bad() {
[i = 0]() { return; };
void init_capture_reassign_bad() {
int i = 0; // this is a dead store
return [i = 0]() { return i; }
();
}
void init_capture_no_call_bad() {
[i = 0]() { return i; };
}
int FN_init_capture_no_read_bad() {
return [i = 0]() { return 0; }
();
}
int return_ok() {
@ -167,8 +178,44 @@ int FN_capture_by_ref_reuseBad() {
return x;
}
void init_capture_ok() {
[i = 0]() { return i; };
int init_capture1_ok() {
return [i = 0]() { return i; }
();
}
int init_capture2_ok() {
int i = 0;
return [j = i]() { return j; }
();
}
int init_capture3_ok() {
int i = 0;
return [i = i]() { return i; }
();
}
int init_capture4_ok() {
int i = 0;
int j = 0;
return [ a = 0, b = i, c = j ]() { return a + b + c; }
();
}
int init_capture5_ok() {
int i = 0;
int k = [j = i]() { return j; }
();
i = 5; // should not be flagged
return i + k;
}
int init_capture6_ok() {
int i = 0;
int k = [i = i + 1]() { return i; }
();
i = 5; // should not be flagged;
return i + k;
}
char* global;
@ -179,4 +226,5 @@ void FP_assign_array_tricky_ok() {
*(int*)arr = 123; // think this is a bug in the frontend... this instruction
// looks like &arr:int = 123
}
}

@ -2,7 +2,9 @@ codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::FP_assign_array_tricky_
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]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::lambda_bad::lambda_dead_stores.cpp:128:11_operator(), 1, DEAD_STORE, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::init_capture_no_call_bad, 1, DEAD_STORE, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::init_capture_reassign_bad, 1, DEAD_STORE, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::lambda_bad::lambda_dead_stores.cpp:139:11_operator(), 1, DEAD_STORE, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus1_bad, 2, DEAD_STORE, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus2_bad, 2, DEAD_STORE, [Write of unused value]
codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus3_bad, 2, DEAD_STORE, [Write of unused value]

@ -39,6 +39,13 @@ int capture_by_ref() {
return x;
}
void init_capture() {
[i = 0]() { i; };
int init_capture1() {
return [i = 0]() { return i; }
();
}
int init_capture2() {
int i = 0;
return [ a = i, b = 0, c = 3 ]() { return a + b + c; }
();
}

@ -87,13 +87,48 @@ digraph iCFG {
"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_capture1#_Z13init_capture1v.7519553572919eb8fa8af50760159e66_1" [label="1: Start init_capture1\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" ;
"init_capture#_Z12init_capturev.b56a308a8fe2b749cb39e3b566237ec2_2" [label="2: Exit init_capture \n " color=yellow style=filled]
"init_capture1#_Z13init_capture1v.7519553572919eb8fa8af50760159e66_1" -> "init_capture1#_Z13init_capture1v.7519553572919eb8fa8af50760159e66_3" ;
"init_capture1#_Z13init_capture1v.7519553572919eb8fa8af50760159e66_2" [label="2: Exit init_capture1 \n " color=yellow style=filled]
"init_capture1#_Z13init_capture1v.7519553572919eb8fa8af50760159e66_3" [label="3: DeclStmt \n *&i:int=0 [line 43]\n " shape="box"]
"init_capture1#_Z13init_capture1v.7519553572919eb8fa8af50760159e66_3" -> "init_capture1#_Z13init_capture1v.7519553572919eb8fa8af50760159e66_4" ;
"init_capture1#_Z13init_capture1v.7519553572919eb8fa8af50760159e66_4" [label="4: Return Stmt \n n$0=_fun_init_capture1::lambda_shared_lambda_lambda1.cpp:43:10_operator()((_fun_init_capture1::lambda_shared_lambda_lambda1.cpp:43:10_operator(),&i):init_capture1::lambda_shared_lambda_lambda1.cpp:43:10) [line 43]\n *&return:int=n$0 [line 43]\n " shape="box"]
"init_capture1#_Z13init_capture1v.7519553572919eb8fa8af50760159e66_4" -> "init_capture1#_Z13init_capture1v.7519553572919eb8fa8af50760159e66_2" ;
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_1" [label="1: Start init_capture2\nFormals: \nLocals: i:int \n DECLARE_LOCALS(&return,&i); [line 47]\n " color=yellow style=filled]
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_1" -> "init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_7" ;
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_2" [label="2: Exit init_capture2 \n " color=yellow style=filled]
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_3" [label="3: DeclStmt \n *&c:int=3 [line 49]\n " shape="box"]
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_3" -> "init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_6" ;
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_4" [label="4: DeclStmt \n *&b:int=0 [line 49]\n " shape="box"]
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_4" -> "init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_3" ;
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_5" [label="5: DeclStmt \n n$0=*&i:int [line 49]\n *&a:int=n$0 [line 49]\n " shape="box"]
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_5" -> "init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_4" ;
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_6" [label="6: Return Stmt \n n$1=_fun_init_capture2::lambda_shared_lambda_lambda1.cpp:49:10_operator()((_fun_init_capture2::lambda_shared_lambda_lambda1.cpp:49:10_operator(),&a,&b,&c):init_capture2::lambda_shared_lambda_lambda1.cpp:49:10) [line 49]\n *&return:int=n$1 [line 49]\n " shape="box"]
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_6" -> "init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_2" ;
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_7" [label="7: DeclStmt \n *&i:int=0 [line 48]\n " shape="box"]
"init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_7" -> "init_capture2#_Z13init_capture2v.ea2bbe7e5f5b3cec548b40ebd7beb345_5" ;
"operator()#lambda_shared_lambda_lambda1.cpp:11:15#bar#(_ZZ3barvENK3$_0clEv).6e24f7d75fa4d9b98ee11419b33635ae_1" [label="1: Start bar::lambda_shared_lambda_lambda1.cpp:11:15_operator()\nFormals: this:bar::lambda_shared_lambda_lambda1.cpp:11:15*\nLocals: i:int \n DECLARE_LOCALS(&return,&i); [line 11]\n " color=yellow style=filled]
@ -192,11 +227,26 @@ digraph iCFG {
"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:43:10#init_capture1#(_ZZ13init_capture1vENK3$_6clEv).184e351188c1ce3cde6eb3d7757baeac_1" [label="1: Start init_capture1::lambda_shared_lambda_lambda1.cpp:43:10_operator()\nFormals: this:init_capture1::lambda_shared_lambda_lambda1.cpp:43:10*\nLocals: \n DECLARE_LOCALS(&return); [line 43]\n " color=yellow style=filled]
"operator()#lambda_shared_lambda_lambda1.cpp:43:10#init_capture1#(_ZZ13init_capture1vENK3$_6clEv).184e351188c1ce3cde6eb3d7757baeac_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:43:10#init_capture1#(_ZZ13init_capture1vENK3$_6clEv).184e351188c1ce3cde6eb3d7757baeac_3" ;
"operator()#lambda_shared_lambda_lambda1.cpp:43:10#init_capture1#(_ZZ13init_capture1vENK3$_6clEv).184e351188c1ce3cde6eb3d7757baeac_2" [label="2: Exit init_capture1::lambda_shared_lambda_lambda1.cpp:43:10_operator() \n " color=yellow style=filled]
"operator()#lambda_shared_lambda_lambda1.cpp:43:10#init_capture1#(_ZZ13init_capture1vENK3$_6clEv).184e351188c1ce3cde6eb3d7757baeac_3" [label="3: Return Stmt \n n$0=*&i:int [line 43]\n *&return:int=n$0 [line 43]\n " shape="box"]
"operator()#lambda_shared_lambda_lambda1.cpp:43:10#init_capture1#(_ZZ13init_capture1vENK3$_6clEv).184e351188c1ce3cde6eb3d7757baeac_3" -> "operator()#lambda_shared_lambda_lambda1.cpp:43:10#init_capture1#(_ZZ13init_capture1vENK3$_6clEv).184e351188c1ce3cde6eb3d7757baeac_2" ;
"operator()#lambda_shared_lambda_lambda1.cpp:49:10#init_capture2#(_ZZ13init_capture2vENK3$_7clEv).1c25acd20a722db722068b75ba66296b_1" [label="1: Start init_capture2::lambda_shared_lambda_lambda1.cpp:49:10_operator()\nFormals: this:init_capture2::lambda_shared_lambda_lambda1.cpp:49:10*\nLocals: \n DECLARE_LOCALS(&return); [line 49]\n " color=yellow style=filled]
"operator()#lambda_shared_lambda_lambda1.cpp:49:10#init_capture2#(_ZZ13init_capture2vENK3$_7clEv).1c25acd20a722db722068b75ba66296b_1" -> "operator()#lambda_shared_lambda_lambda1.cpp:49:10#init_capture2#(_ZZ13init_capture2vENK3$_7clEv).1c25acd20a722db722068b75ba66296b_3" ;
"operator()#lambda_shared_lambda_lambda1.cpp:49:10#init_capture2#(_ZZ13init_capture2vENK3$_7clEv).1c25acd20a722db722068b75ba66296b_2" [label="2: Exit init_capture2::lambda_shared_lambda_lambda1.cpp:49:10_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]
"operator()#lambda_shared_lambda_lambda1.cpp:49:10#init_capture2#(_ZZ13init_capture2vENK3$_7clEv).1c25acd20a722db722068b75ba66296b_3" [label="3: Return Stmt \n n$0=*&a:int [line 49]\n n$1=*&b:int [line 49]\n n$2=*&c:int [line 49]\n *&return:int=((n$0 + n$1) + n$2) [line 49]\n " shape="box"]
"operator()#lambda_shared_lambda_lambda1.cpp:49:10#init_capture2#(_ZZ13init_capture2vENK3$_7clEv).1c25acd20a722db722068b75ba66296b_3" -> "operator()#lambda_shared_lambda_lambda1.cpp:49:10#init_capture2#(_ZZ13init_capture2vENK3$_7clEv).1c25acd20a722db722068b75ba66296b_2" ;
}

Loading…
Cancel
Save