[frontend] Record attribute unused in local variable data

Summary: To avoid dead store false positives we skip initialization of a variable that has an `unused` attribute. However, this causes uninitialized value false positives when the variable is later used in macros. To fix this, instead of skipping initialization we record the information about `unused` attribute in local variable data that we can later use for filtering out dead store issues.

Reviewed By: jvillard

Differential Revision: D22868050

fbshipit-source-id: 4a2d0e680
master
Daiva Naudziuniene 4 years ago committed by Facebook GitHub Bot
parent 59592a60e4
commit 35de604422

@ -29,12 +29,13 @@ let pp_objc_accessor_type fmt objc_accessor_type =
annots
type var_data = {name: Mangled.t; typ: Typ.t; modify_in_block: bool; is_constexpr: bool}
type var_data =
{name: Mangled.t; typ: Typ.t; modify_in_block: bool; is_constexpr: bool; is_declared_unused: bool}
[@@deriving compare]
let pp_var_data fmt {name; typ; modify_in_block} =
F.fprintf fmt "@[<h>{ name=@ %a;@ typ=@ %a;@ modify_in_block=@ %b@ }@]" Mangled.pp name
(Typ.pp_full Pp.text) typ modify_in_block
let pp_var_data fmt {name; typ; modify_in_block; is_declared_unused} =
F.fprintf fmt "@[<h>{ name=@ %a;@ typ=@ %a;@ modify_in_block=@ %b;@ is_declared_unused=@ %b@ }@]"
Mangled.pp name (Typ.pp_full Pp.text) typ modify_in_block is_declared_unused
type t =

@ -17,7 +17,8 @@ type var_data =
; modify_in_block: bool
(** __block attribute of Objective-C variables, means that it will be modified inside a
block *)
; is_constexpr: bool }
; is_constexpr: bool
; is_declared_unused: bool (** variable declared with attribute [unused] *) }
type t =
{ access: PredSymb.access (** visibility access *)

@ -236,14 +236,16 @@ let checker {IntraproceduralAnalysis.proc_desc; err_log} =
false
in
let locals = Procdesc.get_locals proc_desc in
let is_constexpr pvar =
let is_constexpr_or_unused pvar =
List.find locals ~f:(fun local_data ->
Mangled.equal (Pvar.get_name pvar) local_data.ProcAttributes.name )
|> Option.exists ~f:(fun local -> local.ProcAttributes.is_constexpr)
|> Option.exists ~f:(fun local ->
local.ProcAttributes.is_constexpr || local.ProcAttributes.is_declared_unused )
in
let should_report pvar typ live_vars captured_by_ref_vars =
not
( Pvar.is_frontend_tmp pvar || Pvar.is_return pvar || Pvar.is_global pvar || is_constexpr pvar
( Pvar.is_frontend_tmp pvar || Pvar.is_return pvar || Pvar.is_global pvar
|| is_constexpr_or_unused 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

@ -205,7 +205,12 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
CVar_decl.mk_temp_sil_var_for_expr context ~name:var_name ~clang_pointer expr_info
in
let var_data =
ProcAttributes.{name= Pvar.get_name pvar; typ; modify_in_block= false; is_constexpr= false}
ProcAttributes.
{ name= Pvar.get_name pvar
; typ
; modify_in_block= false
; is_constexpr= false
; is_declared_unused= false }
in
Procdesc.append_locals procdesc [var_data] ;
(Exp.Lvar pvar, typ)
@ -245,7 +250,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
{ name= Pvar.get_name pvar
; typ= return_type
; modify_in_block= false
; is_constexpr= false }
; is_constexpr= false
; is_declared_unused= false }
in
Procdesc.append_locals procdesc [var_data] ;
Exp.Lvar pvar
@ -1201,7 +1207,11 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
let pvar = Pvar.mk_tmp "__temp_construct_" (Procdesc.get_proc_name procdesc) in
let class_type = CType_decl.get_type_from_expr_info ei context.CContext.tenv in
let var_data : ProcAttributes.var_data =
{name= Pvar.get_name pvar; typ= class_type; modify_in_block= false; is_constexpr= false}
{ name= Pvar.get_name pvar
; typ= class_type
; modify_in_block= false
; is_constexpr= false
; is_declared_unused= false }
in
Procdesc.append_locals procdesc [var_data] ;
(Exp.Lvar pvar, class_type)
@ -1615,7 +1625,11 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
let pvar = CVar_decl.mk_temp_sil_var procdesc ~name:"SIL_temp_conditional___" in
let var_data =
ProcAttributes.
{name= Pvar.get_name pvar; typ= var_typ; modify_in_block= false; is_constexpr= false}
{ name= Pvar.get_name pvar
; typ= var_typ
; modify_in_block= false
; is_constexpr= false
; is_declared_unused= false }
in
Procdesc.append_locals procdesc [var_data] ;
let continuation' = mk_cond_continuation trans_state.continuation in
@ -2435,8 +2449,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
|> mk_trans_result ret_exp_typ
and init_expr_trans ?(is_var_unused = false) ?(is_initListExpr_builtin = false) trans_state
var_exp_typ ?qual_type var_stmt_info init_expr_opt =
and init_expr_trans ?(is_initListExpr_builtin = false) trans_state var_exp_typ ?qual_type
var_stmt_info init_expr_opt =
match init_expr_opt with
| None -> (
match Option.bind qual_type ~f:(fun qt -> CAst_utils.get_type qt.Clang_ast_t.qt_type_ptr) with
@ -2464,8 +2478,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
in
let assign_trans_control_opt =
if
is_var_unused
|| (* variable might be initialized already - do nothing in that case*)
(* 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
@ -2501,21 +2514,18 @@ 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 ~is_var_unused var_decl qual_type vdi next_node =
let do_var_dec 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 ~is_var_unused trans_state' (Exp.Lvar pvar, typ) ~qual_type stmt_info
init_expr_trans 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 `UnusedAttr _ -> true | _ -> false)
in
let rec aux : decl list -> trans_result option = function
| [] ->
None
| (VarDecl ({di_attributes}, _, qt, vdi) as var_decl) :: var_decls' ->
| (VarDecl (_, _, 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 =
@ -2525,8 +2535,7 @@ 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 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
let res_trans_tmp = do_var_dec 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
@ -2895,7 +2904,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
[ { ProcAttributes.name= Pvar.get_name temp
; typ= array_typ
; modify_in_block= false
; is_constexpr= false } ] ;
; is_constexpr= false
; is_declared_unused= false } ] ;
(* 2. Translate array elements *)
let res_trans_elems = List.mapi ~f:(exec_instruction_with_trans_state trans_state None) stmts in
(* 3. Add array initialization (elements assignments) *)
@ -3240,7 +3250,12 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
let res_trans = init_expr_trans trans_state var_exp_typ stmt_info (Some temp_exp) in
let _, typ = res_trans.return in
let var_data =
ProcAttributes.{name= Pvar.get_name pvar; typ; modify_in_block= false; is_constexpr= false}
ProcAttributes.
{ name= Pvar.get_name pvar
; typ
; modify_in_block= false
; is_constexpr= false
; is_declared_unused= false }
in
Procdesc.append_locals procdesc [var_data] ;
res_trans

@ -70,8 +70,11 @@ let add_var_to_locals procdesc var_decl typ pvar =
vdi.Clang_ast_t.vdi_is_const_expr
|| (Typ.is_const typ.Typ.quals && vdi.Clang_ast_t.vdi_is_init_expr_cxx11_constant)
in
let is_declared_unused =
List.exists decl_info.di_attributes ~f:(function `UnusedAttr _ -> true | _ -> false)
in
let var_data : ProcAttributes.var_data =
{name= Pvar.get_name pvar; typ; modify_in_block; is_constexpr}
{name= Pvar.get_name pvar; typ; modify_in_block; is_constexpr; is_declared_unused}
in
Procdesc.append_locals procdesc [var_data]
| _ ->

@ -437,7 +437,8 @@ let create_cm_procdesc source_file program icfg cm proc_name =
let locals_ = translate_locals program tenv formals bytecode jbir_code in
let locals =
List.map locals_ ~f:(fun (name, typ) ->
({name; typ; modify_in_block= false; is_constexpr= false} : ProcAttributes.var_data) )
( {name; typ; modify_in_block= false; is_constexpr= false; is_declared_unused= false}
: ProcAttributes.var_data ) )
in
let method_annotation = JAnnotation.translate_method cm.Javalib.cm_annotations in
let proc_attributes =

@ -344,3 +344,8 @@ void use_uninit_in_expr_bad() {
int x;
int y = x + 2;
}
int unused_attribute_ok() {
int __attribute__((unused)) x = 42;
return x;
}

@ -7,7 +7,7 @@ digraph cfg {
"super_example_main.e3ebe95e6c5ae811733f235c29fbbf6d_2" [label="2: Exit super_example_main \n " color=yellow style=filled]
"super_example_main.e3ebe95e6c5ae811733f235c29fbbf6d_3" [label="3: DeclStmt \n VARIABLE_DECLARED(a:objc_object*); [line 40, column 5]\n n$0=_fun___objc_alloc_no_fail(sizeof(t=ASuper):unsigned long) [line 40, column 21]\n n$1=_fun_NSObject.init(n$0:ASuper*) virtual [line 40, column 21]\n " shape="box"]
"super_example_main.e3ebe95e6c5ae811733f235c29fbbf6d_3" [label="3: DeclStmt \n VARIABLE_DECLARED(a:objc_object*); [line 40, column 5]\n n$0=_fun___objc_alloc_no_fail(sizeof(t=ASuper):unsigned long) [line 40, column 21]\n n$1=_fun_NSObject.init(n$0:ASuper*) virtual [line 40, column 21]\n *&a:objc_object*=n$1 [line 40, column 5]\n " shape="box"]
"super_example_main.e3ebe95e6c5ae811733f235c29fbbf6d_3" -> "super_example_main.e3ebe95e6c5ae811733f235c29fbbf6d_2" ;

Loading…
Cancel
Save