From f8338d8fafa6176a8a59fd0f66ca2d60ec978c10 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Fri, 8 Feb 2019 02:14:29 -0800 Subject: [PATCH] [clang] ignore `__attribute__((unused))` variable initialisations Summary: When a `VarDecl` has the attribute `unused` then do not assign its initialisation result to the corresponding variable. Reviewed By: ngorogiannis Differential Revision: D13974497 fbshipit-source-id: 28029f995 --- infer/src/checkers/liveness.ml | 3 --- infer/src/clang/cTrans.ml | 20 ++++++++++++------- .../cpp/liveness/dead_stores.cpp | 9 ++++----- .../codetoanalyze/cpp/liveness/issues.exp | 1 + 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/infer/src/checkers/liveness.ml b/infer/src/checkers/liveness.ml index c527b0993..e0ac1b3a7 100644 --- a/infer/src/checkers/liveness.ml +++ b/infer/src/checkers/liveness.ml @@ -172,11 +172,8 @@ let checker {Callbacks.tenv; summary; proc_desc} : Summary.t = |> Option.exists ~f:(fun local -> local.ProcAttributes.is_constexpr) in let should_report pvar typ live_vars captured_by_ref_vars = - (* T32000971: a temporay fix for dead store false positives until we support __unused__ attribute *) - let is_unused_tmp_var pvar = String.equal "__tmp" (Pvar.to_string pvar) in not ( Pvar.is_frontend_tmp pvar || Pvar.is_return pvar || Pvar.is_global pvar || is_constexpr pvar - || is_unused_tmp_var pvar || VarSet.mem (Var.of_pvar pvar) captured_by_ref_vars || Domain.mem (Var.of_pvar pvar) live_vars || Procdesc.is_captured_pvar proc_desc pvar diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index a1af81979..5dffc3cc3 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -2220,7 +2220,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s |> mk_trans_result ret_exp_typ - and init_expr_trans trans_state var_exp_typ ?qual_type var_stmt_info init_expr_opt = + and init_expr_trans ?(is_var_unused = false) trans_state var_exp_typ ?qual_type var_stmt_info + init_expr_opt = match init_expr_opt with | None -> ( match @@ -2254,8 +2255,9 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s in let assign_trans_control_opt = if - (* variable might be initialized already - do nothing in that case*) - List.exists ~f:(Exp.equal var_exp) res_trans_ie.control.initd_exps + is_var_unused + || (* variable might be initialized already - do nothing in that case*) + List.exists ~f:(Exp.equal var_exp) res_trans_ie.control.initd_exps then None else let sil_e1', ie_typ = res_trans_ie.return in @@ -2292,18 +2294,21 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s let context = trans_state.context in let procdesc = context.CContext.procdesc in let procname = Procdesc.get_proc_name procdesc in - let do_var_dec var_decl qual_type vdi next_node = + let do_var_dec ~is_var_unused var_decl qual_type vdi next_node = let pvar = CVar_decl.sil_var_of_decl context var_decl procname in let typ = CType_decl.qual_type_to_sil_type context.CContext.tenv qual_type in CVar_decl.add_var_to_locals procdesc var_decl typ pvar ; let trans_state' = {trans_state with succ_nodes= next_node} in - init_expr_trans trans_state' (Exp.Lvar pvar, typ) ~qual_type stmt_info + init_expr_trans ~is_var_unused trans_state' (Exp.Lvar pvar, typ) ~qual_type stmt_info vdi.Clang_ast_t.vdi_init_expr in + let has_unused_attr attributes = + List.exists attributes ~f:(function Clang_ast_t.UnusedAttr _ -> true | _ -> false) + in let rec aux : decl list -> trans_result option = function | [] -> None - | (VarDecl (_, _, qt, vdi) as var_decl) :: var_decls' -> + | (VarDecl ({di_attributes}, _, qt, vdi) as var_decl) :: var_decls' -> (* Var are defined when procdesc is created, here we only take care of initialization *) let res_trans_tl = aux var_decls' in let root_nodes_tl, instrs_tl, initd_exps_tl = @@ -2313,7 +2318,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s | Some {control= {root_nodes; instrs; initd_exps}} -> (root_nodes, instrs, initd_exps) in - let res_trans_tmp = do_var_dec var_decl qt vdi root_nodes_tl in + let is_var_unused = has_unused_attr di_attributes in + let res_trans_tmp = do_var_dec ~is_var_unused var_decl qt vdi root_nodes_tl in (* keep the last return and leaf_nodes from the list *) let return, leaf_nodes = match res_trans_tl with diff --git a/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp b/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp index a004cebb1..fdb8ab2a3 100644 --- a/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp +++ b/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp @@ -484,18 +484,17 @@ class Exceptions { void init_in_binop_bad(int x) { x = -x & ~int{0}; } -void FN_unused_tmp_bad() { - // T32000971 - int __tmp = 1; -} +void unused_tmp_bad() { int __tmp = 1; } #define UNUSED(a) __typeof__(&a) __attribute__((unused)) __tmp = &a; -void unused_attribute_ok() { +void unused_attribute_tmp_ok() { int x; UNUSED(x); } +void unused_attribute_ok() { int __attribute__((unused)) x = 42; } + struct ChainedCalls { ChainedCalls chained(int i); }; diff --git a/infer/tests/codetoanalyze/cpp/liveness/issues.exp b/infer/tests/codetoanalyze/cpp/liveness/issues.exp index 7edd4a1d7..676977fcd 100644 --- a/infer/tests/codetoanalyze/cpp/liveness/issues.exp +++ b/infer/tests/codetoanalyze/cpp/liveness/issues.exp @@ -18,6 +18,7 @@ codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus1_bad, 2, DEAD codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus2_bad, 2, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus3_bad, 2, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::reassign_param_bad, 0, DEAD_STORE, no_bucket, ERROR, [Write of unused value] +codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::unused_tmp_bad, 0, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::use_then_dead_bad, 3, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores_constexpr.cpp, capture_const_bad, 1, DEAD_STORE, no_bucket, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/non_type_template_param.cpp, X<3>_isZeroBad, 1, DEAD_STORE, no_bucket, ERROR, [Write of unused value]