|
|
@ -61,6 +61,25 @@ end
|
|
|
|
module CFG = ProcCfg.OneInstrPerNode (ProcCfg.Backward (ProcCfg.Exceptional))
|
|
|
|
module CFG = ProcCfg.OneInstrPerNode (ProcCfg.Backward (ProcCfg.Exceptional))
|
|
|
|
module Analyzer = AbstractInterpreter.Make (CFG) (TransferFunctions)
|
|
|
|
module Analyzer = AbstractInterpreter.Make (CFG) (TransferFunctions)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let is_captured_var procdesc pvar =
|
|
|
|
|
|
|
|
let procname = Procdesc.get_proc_name procdesc in
|
|
|
|
|
|
|
|
let pvar_name = Pvar.get_name pvar in
|
|
|
|
|
|
|
|
let pvar_matches (name, _) = Mangled.equal name pvar_name in
|
|
|
|
|
|
|
|
let is_captured_var_cpp_lambda =
|
|
|
|
|
|
|
|
(* var is captured if the procedure is a lambda and the var is not in the locals or formals *)
|
|
|
|
|
|
|
|
Typ.Procname.is_cpp_lambda procname
|
|
|
|
|
|
|
|
&& not
|
|
|
|
|
|
|
|
( List.exists ~f:pvar_matches (Procdesc.get_locals procdesc)
|
|
|
|
|
|
|
|
|| List.exists ~f:pvar_matches (Procdesc.get_formals procdesc) )
|
|
|
|
|
|
|
|
in
|
|
|
|
|
|
|
|
let is_captured_var_objc_block =
|
|
|
|
|
|
|
|
(* var is captured if the procedure is a objc block and the var is in the captured *)
|
|
|
|
|
|
|
|
Typ.Procname.is_objc_block procname
|
|
|
|
|
|
|
|
&& List.exists ~f:pvar_matches (Procdesc.get_captured procdesc)
|
|
|
|
|
|
|
|
in
|
|
|
|
|
|
|
|
is_captured_var_cpp_lambda || is_captured_var_objc_block
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let is_whitelisted_var var =
|
|
|
|
let is_whitelisted_var var =
|
|
|
|
let whitelisted_vars = ["__assert_file__"; "__assert_fn__"] in
|
|
|
|
let whitelisted_vars = ["__assert_file__"; "__assert_fn__"] in
|
|
|
|
List.exists
|
|
|
|
List.exists
|
|
|
@ -73,24 +92,11 @@ let checker {Callbacks.tenv; summary; proc_desc} : Specs.summary =
|
|
|
|
let invariant_map =
|
|
|
|
let invariant_map =
|
|
|
|
Analyzer.exec_cfg cfg (ProcData.make_default proc_desc tenv) ~initial:Domain.empty ~debug:true
|
|
|
|
Analyzer.exec_cfg cfg (ProcData.make_default proc_desc tenv) ~initial:Domain.empty ~debug:true
|
|
|
|
in
|
|
|
|
in
|
|
|
|
let procname = Procdesc.get_proc_name proc_desc in
|
|
|
|
|
|
|
|
let is_cpp_lambda =
|
|
|
|
|
|
|
|
String.is_substring ~substring:"operator()" (Typ.Procname.get_method procname)
|
|
|
|
|
|
|
|
in
|
|
|
|
|
|
|
|
let is_captured_var pvar =
|
|
|
|
|
|
|
|
let pvar_name = Pvar.get_name pvar in
|
|
|
|
|
|
|
|
let pvar_matches (name, _) = Mangled.equal name pvar_name in
|
|
|
|
|
|
|
|
(* var is captured if the procedure is a lambda and the var is not in the locals or formals *)
|
|
|
|
|
|
|
|
is_cpp_lambda
|
|
|
|
|
|
|
|
&& not
|
|
|
|
|
|
|
|
( List.exists ~f:pvar_matches (Procdesc.get_locals proc_desc)
|
|
|
|
|
|
|
|
|| List.exists ~f:pvar_matches (Procdesc.get_formals proc_desc) )
|
|
|
|
|
|
|
|
in
|
|
|
|
|
|
|
|
let report_dead_store live_vars = function
|
|
|
|
let report_dead_store live_vars = function
|
|
|
|
| Sil.Store (Lvar pvar, _, _, loc)
|
|
|
|
| Sil.Store (Lvar pvar, _, _, loc)
|
|
|
|
when not
|
|
|
|
when not
|
|
|
|
( Pvar.is_frontend_tmp pvar || Pvar.is_return pvar || Pvar.is_global pvar
|
|
|
|
( Pvar.is_frontend_tmp pvar || Pvar.is_return pvar || Pvar.is_global pvar
|
|
|
|
|| Domain.mem (Var.of_pvar pvar) live_vars || is_captured_var pvar
|
|
|
|
|| Domain.mem (Var.of_pvar pvar) live_vars || is_captured_var proc_desc pvar
|
|
|
|
|| is_whitelisted_var pvar ) ->
|
|
|
|
|| is_whitelisted_var pvar ) ->
|
|
|
|
let issue_id = IssueType.dead_store.unique_id in
|
|
|
|
let issue_id = IssueType.dead_store.unique_id in
|
|
|
|
let message = F.asprintf "The value written to %a is never used" (Pvar.pp Pp.text) pvar in
|
|
|
|
let message = F.asprintf "The value written to %a is never used" (Pvar.pp Pp.text) pvar in
|
|
|
@ -114,3 +120,4 @@ let checker {Callbacks.tenv; summary; proc_desc} : Specs.summary =
|
|
|
|
in
|
|
|
|
in
|
|
|
|
List.iter (CFG.nodes cfg) ~f:report_on_node ;
|
|
|
|
List.iter (CFG.nodes cfg) ~f:report_on_node ;
|
|
|
|
summary
|
|
|
|
summary
|
|
|
|
|
|
|
|
|
|
|
|