[dead stores] config file for custom scope guard types

Reviewed By: da319

Differential Revision: D6517706

fbshipit-source-id: 3b6f805
master
Sam Blackshear 7 years ago committed by Facebook Github Bot
parent 432fa4913c
commit 647e1cd62d

@ -975,6 +975,12 @@ and cxx_infer_headers =
"Include C++ header models during compilation. Infer swaps some C++ headers for its own in order to get a better model of, eg, the standard library. This can sometimes cause compilation failures." "Include C++ header models during compilation. Infer swaps some C++ headers for its own in order to get a better model of, eg, the standard library. This can sometimes cause compilation failures."
and cxx_scope_guards =
CLOpt.mk_json ~long:"cxx-scope-guards"
~in_help:CLOpt.([(Analyze, manual_clang)])
"Specify scope guard classes that can be read only by destructors without being reported as dead stores."
and cxx = and cxx =
CLOpt.mk_bool ~long:"cxx" ~default:true CLOpt.mk_bool ~long:"cxx" ~default:true
~in_help:CLOpt.([(Capture, manual_clang)]) ~in_help:CLOpt.([(Capture, manual_clang)])
@ -2347,6 +2353,8 @@ and cxx = !cxx
and cxx_infer_headers = !cxx_infer_headers and cxx_infer_headers = !cxx_infer_headers
and cxx_scope_guards = !cxx_scope_guards
and debug_level_analysis = !debug_level_analysis and debug_level_analysis = !debug_level_analysis
and debug_level_capture = !debug_level_capture and debug_level_capture = !debug_level_capture

@ -356,6 +356,8 @@ val cxx : bool
val cxx_infer_headers : bool val cxx_infer_headers : bool
val cxx_scope_guards : Yojson.Basic.json
val debug_level_analysis : int val debug_level_analysis : int
val debug_level_capture : int val debug_level_capture : int

@ -85,27 +85,19 @@ 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 checker {Callbacks.tenv; summary; proc_desc} : Specs.summary = (* It's fine to have a dead store on a type that uses the "scope guard" pattern. These types
let cfg = CFG.from_pdesc proc_desc in are only read in their destructors, and this is expected/ok.
let invariant_map = (e.g., https://github.com/facebook/folly/blob/master/folly/ScopeGuard.h). *)
Analyzer.exec_cfg cfg (ProcData.make_default proc_desc tenv) ~initial:Domain.empty ~debug:true let matcher_scope_guard =
in let of_json init = function
(* we don't want to report in harmless cases like int i = 0; if (...) { i = ... } else { i = ... } | `List scope_guards ->
that create an intentional dead store as an attempt to imitate default value semantics. List.fold scope_guards ~f:(fun acc json -> Yojson.Basic.Util.to_string json :: acc) ~init
use dead stores to a "sentinel" value as a heuristic for ignoring this case *)
let is_sentinel_exp = function
| Exp.Const Cint i ->
IntLit.iszero i || IntLit.isnull i
| Exp.Const Cfloat 0.0 ->
true
| _ -> | _ ->
false init
in in
let matcher_scope_guard = let default_scope_guards =
QualifiedCppName.Match.of_fuzzy_qual_names
[ (* C++ *) [ (* C++ *)
"faiss::ScopeDeleter" "folly::RWSpinLock::ReadHolder"
; "folly::RWSpinLock::ReadHolder"
; "folly::RWSpinLock::WriteHolder" ; "folly::RWSpinLock::WriteHolder"
; "folly::ScopeGuard" ; "folly::ScopeGuard"
; "folly::SharedMutex::ReadHolder" ; "folly::SharedMutex::ReadHolder"
@ -120,9 +112,26 @@ let checker {Callbacks.tenv; summary; proc_desc} : Specs.summary =
; "std::unique_lock" (* Obj-C *) ; "std::unique_lock" (* Obj-C *)
; "CKComponentScope" ] ; "CKComponentScope" ]
in in
(* It's fine to have a dead store on a type that uses the "scope guard" pattern. These types of_json default_scope_guards Config.cxx_scope_guards
are only read in their destructors, and this is expected/ok. |> QualifiedCppName.Match.of_fuzzy_qual_names
(e.g., https://github.com/facebook/folly/blob/master/folly/ScopeGuard.h). *)
let checker {Callbacks.tenv; summary; proc_desc} : Specs.summary =
let cfg = CFG.from_pdesc proc_desc in
let invariant_map =
Analyzer.exec_cfg cfg (ProcData.make_default proc_desc tenv) ~initial:Domain.empty ~debug:true
in
(* we don't want to report in harmless cases like int i = 0; if (...) { i = ... } else { i = ... }
that create an intentional dead store as an attempt to imitate default value semantics.
use dead stores to a "sentinel" value as a heuristic for ignoring this case *)
let is_sentinel_exp = function
| Exp.Const Cint i ->
IntLit.iszero i || IntLit.isnull i
| Exp.Const Cfloat 0.0 ->
true
| _ ->
false
in
let rec is_scope_guard = function let rec is_scope_guard = function
| {Typ.desc= Tstruct name} -> | {Typ.desc= Tstruct name} ->
QualifiedCppName.Match.match_qualifiers matcher_scope_guard (Typ.Name.qual_name name) QualifiedCppName.Match.match_qualifiers matcher_scope_guard (Typ.Name.qual_name name)
@ -169,3 +178,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

@ -0,0 +1,5 @@
{
"cxx-scope-guards": [
"infer::ScopeGuard"
]
}

@ -11,6 +11,10 @@
#include <new> #include <new>
#include <thread> #include <thread>
namespace infer {
class ScopeGuard {};
}; // namespace infer
namespace folly { namespace folly {
class ScopeGuard {}; class ScopeGuard {};
@ -301,6 +305,8 @@ void read_holder_ok() { folly::SharedMutex::ReadHolder guard; }
void write_holder_ok() { folly::SharedMutex::WriteHolder guard; } void write_holder_ok() { folly::SharedMutex::WriteHolder guard; }
void custom_scope_guard_ok() { infer::ScopeGuard guard; }
struct S { struct S {
~S() {} ~S() {}
}; };

@ -6,7 +6,7 @@ codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::dead_then_live_bad, 1,
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::easy_bad, 0, 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_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::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:160:11_operator(), 1, DEAD_STORE, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::lambda_bad::lambda_dead_stores.cpp:164: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_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_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] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus3_bad, 2, DEAD_STORE, [Write of unused value]

Loading…
Cancel
Save