[starvation] template filters

Reviewed By: jvillard

Differential Revision: D14044735

fbshipit-source-id: 84acf3c1f
master
Nikos Gorogiannis 6 years ago committed by Facebook Github Bot
parent ea530390d3
commit b243fae86c

@ -8,6 +8,19 @@
open! IStd
module L = Logging
let template_arg = Str.regexp "<[^<>]*>"
let rec strip_template_args str =
if
(not (String.contains str '<'))
|| String.equal str Typ.Procname.Java.constructor_method_name
|| String.equal str Typ.Procname.Java.class_initializer_method_name
then str
else
let result = Str.global_replace template_arg "" str in
if String.equal result str then str else strip_template_args result
(** [call_matches <named args> C methods] builds a method matcher for calls [C.foo] where
[foo] is in [methods]. Named arguments change behaviour:
- [search_superclasses=true] will match calls [S.foo] where [S] is a superclass of [C].
@ -15,25 +28,30 @@ module L = Logging
- [actuals_pred] is a predicate that runs on the expressions fed as arguments to the call, and
which must return [true] for the matcher to return [true]. *)
let call_matches ~search_superclasses ~method_prefix ~actuals_pred clazz methods =
let clazz = strip_template_args clazz in
let methods = List.map methods ~f:strip_template_args in
let method_matcher =
if method_prefix then fun current_method target_method ->
String.is_prefix current_method ~prefix:target_method
else fun current_method target_method -> String.equal current_method target_method
String.is_prefix ~prefix:target_method current_method
else fun current_method target_method -> String.equal target_method current_method
in
let class_matcher =
if search_superclasses then
let target = "class " ^ clazz in
let is_target tname _tstruct = Typ.Name.to_string tname |> String.equal target in
let is_target tname _tstruct =
Typ.Name.to_string tname |> strip_template_args |> String.equal target
in
fun tenv pname ->
Typ.Procname.get_class_type_name pname
|> Option.exists ~f:(PatternMatch.supertype_exists tenv is_target)
else fun _tenv pname ->
Typ.Procname.get_class_name pname |> Option.exists ~f:(String.equal clazz)
Typ.Procname.get_class_name pname |> Option.map ~f:strip_template_args
|> Option.exists ~f:(String.equal clazz)
in
(fun tenv pn actuals ->
actuals_pred actuals
&&
let mthd = Typ.Procname.get_method pn in
let mthd = Typ.Procname.get_method pn |> strip_template_args in
List.exists methods ~f:(method_matcher mthd) && class_matcher tenv pn )
|> Staged.stage

@ -7,7 +7,8 @@
open! IStd
(** pattern matcher for Java methods *)
(** pattern matcher for Java/C++ methods
NB matching is modulo template arguments in C++ classes and functions *)
type t = Tenv.t -> Typ.Procname.t -> HilExp.t list -> bool
type record =

@ -1,4 +1,7 @@
{
"force-delete-results-dir": true,
"starvation-skip-analysis" : [ { "classname": "skipped::Skip", "methods": ["skipped_ok"] } ]
"starvation-skip-analysis" : [
{ "classname": "skipped::Skip", "methods": ["skipped_ok"] },
{ "classname": "skipped::SkipTemplate", "methods": ["skipped_ok"] }
]
}

@ -4,4 +4,6 @@ codetoanalyze/cpp/starvation/basics.cpp, basics::SelfDeadlock_complicated_bad, 1
codetoanalyze/cpp/starvation/basics.cpp, basics::SelfDeadlock_interproc1_bad, 114, DEADLOCK, no_bucket, ERROR, [In method `basics::SelfDeadlock_interproc1_bad`, locks `this.mutex_` in `class basics::SelfDeadlock`,Method call: `basics::SelfDeadlock_interproc2_bad`, locks `this.mutex_` in `class basics::SelfDeadlock`]
codetoanalyze/cpp/starvation/basics.cpp, basics::SelfDeadlock_thread_bad, 105, DEADLOCK, no_bucket, ERROR, [In method `basics::SelfDeadlock_thread_bad`, locks `this.mutex_` in `class basics::SelfDeadlock`, locks `this.mutex_` in `class basics::SelfDeadlock`]
codetoanalyze/cpp/starvation/basics.cpp, basics::WithGuard_thread1_bad, 44, DEADLOCK, no_bucket, ERROR, [[Trace 1] `basics::WithGuard_thread1_bad`, locks `this.mutex_1` in `class basics::WithGuard`, locks `this.mutex_2` in `class basics::WithGuard`,[Trace 2] `basics::WithGuard_thread2_bad`, locks `this.mutex_2` in `class basics::WithGuard`, locks `this.mutex_1` in `class basics::WithGuard`]
codetoanalyze/cpp/starvation/skip.cpp, skipped::SkipTemplate<void>_not_skipped_bad, 44, DEADLOCK, no_bucket, ERROR, [In method `skipped::SkipTemplate<void>_not_skipped_bad`,Method call: `skipped::SkipTemplate<void>_private_deadlock`, locks `this.mutex_` in `class skipped::SkipTemplate<void>`, locks `this.mutex_` in `class skipped::SkipTemplate<void>`]
codetoanalyze/cpp/starvation/skip.cpp, skipped::Skip_not_skipped_bad, 19, DEADLOCK, no_bucket, ERROR, [In method `skipped::Skip_not_skipped_bad`,Method call: `skipped::Skip_private_deadlock`, locks `this.mutex_` in `class skipped::Skip`, locks `this.mutex_` in `class skipped::Skip`]
codetoanalyze/cpp/starvation/skip.cpp, skipped::UseTemplate_foo, 53, DEADLOCK, no_bucket, ERROR, [In method `skipped::UseTemplate_foo`,Method call: `skipped::SkipTemplate<void>_not_skipped_bad`,Method call: `skipped::SkipTemplate<void>_private_deadlock`, locks `this.mutex_` in `class skipped::SkipTemplate<void>`, locks `this.mutex_` in `class skipped::SkipTemplate<void>`]

@ -7,7 +7,7 @@
#include <mutex>
// the deadlock here is masked by the starvation-skip-analysis option in
// the deadlocks here are masked by the starvation-skip-analysis option in
// .inferconfig
namespace skipped {
class Skip {
@ -27,4 +27,31 @@ class Skip {
}
};
template <class T>
class SkipTemplate {
private:
T* a_;
std::mutex mutex_;
void private_deadlock() {
std::lock_guard<std::mutex> l(mutex_);
{ std::lock_guard<std::mutex> l(mutex_); }
}
public:
void skipped_ok() { private_deadlock(); }
void not_skipped_bad() { private_deadlock(); }
};
class UseTemplate {
public:
void foo() {
SkipTemplate<void> x;
x.skipped_ok();
x.not_skipped_bad();
}
};
} // namespace skipped

Loading…
Cancel
Save