From 5134ea36ed5b2191edaea1f431964ee93df95f22 Mon Sep 17 00:00:00 2001 From: Sam Blackshear Date: Tue, 7 Mar 2017 09:47:36 -0800 Subject: [PATCH] [thread-safety] enable defining aliases of @ThreadSafe in .inferconfig Reviewed By: peterogithub Differential Revision: D4662764 fbshipit-source-id: c202509 --- infer/src/base/Config.ml | 6 +++++ infer/src/base/Config.mli | 1 + infer/src/checkers/ThreadSafety.ml | 14 ++++++++--- infer/src/checkers/ThreadSafetyConfig.ml | 19 ++++++++++++++ infer/src/checkers/ThreadSafetyConfig.mli | 18 +++++++++++++ .../java/threadsafety/.inferconfig | 3 +++ .../java/threadsafety/Annotations.java | 25 +++++++++++++++++++ .../java/threadsafety/issues.exp | 2 ++ 8 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 infer/src/checkers/ThreadSafetyConfig.ml create mode 100644 infer/src/checkers/ThreadSafetyConfig.mli create mode 100644 infer/tests/codetoanalyze/java/threadsafety/.inferconfig diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 8a2b26c08..0f636cb78 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -1297,6 +1297,11 @@ and testing_mode = CLOpt.mk_bool ~deprecated:["testing_mode"; "-testing_mode"] ~long:"testing-mode" ~short:"tm" "Mode for testing, where no headers are translated, and dot files are created (clang only)" +and threadsafe_aliases = + CLOpt.mk_json ~long:"threadsafe-aliases" + ~parse_mode:CLOpt.(Infer [Checkers]) + "Specify custom annotations that should be considered aliases of @ThreadSafe" + and trace_join = CLOpt.mk_bool ~deprecated:["trace_join"] ~long:"trace-join" "Detailed tracing information during prop join operations" @@ -1656,6 +1661,7 @@ and test = !test and test_filtering = !test_filtering and testing_mode = !testing_mode and threadsafety = !threadsafety +and threadsafe_aliases = !threadsafe_aliases and trace_error = !trace_error and trace_ondemand = !trace_ondemand and trace_join = !trace_join diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index 32adcca68..da60b9da4 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -322,6 +322,7 @@ val test : bool val test_filtering : bool val testing_mode : bool val threadsafety : bool +val threadsafe_aliases : Yojson.Basic.json val trace_error : bool val trace_ondemand : bool val trace_join : bool diff --git a/infer/src/checkers/ThreadSafety.ml b/infer/src/checkers/ThreadSafety.ml index 904936a41..cebefe00d 100644 --- a/infer/src/checkers/ThreadSafety.ml +++ b/infer/src/checkers/ThreadSafety.ml @@ -679,11 +679,19 @@ let runs_on_ui_thread proc_desc = Annotations.ia_is_on_unbind annot || Annotations.ia_is_on_unmount annot) +let threadsafe_annotations = + Annotations.thread_safe :: + (ThreadSafetyConfig.AnnotationAliases.of_json Config.threadsafe_aliases) -(* returns true if the annotation is @ThreadSafe or @ThreadSafe(enableChecks = true) *) +(* returns true if the annotation is @ThreadSafe, @ThreadSafe(enableChecks = true), or is defined + as an alias of @ThreadSafe in a .inferconfig file. *) let is_thread_safe item_annot = - let f (annot, _) = - Annotations.annot_ends_with annot Annotations.thread_safe && + let f ((annot : Annot.t), _) = + List.exists + ~f:(fun annot_string -> + Annotations.annot_ends_with annot annot_string || + String.equal annot.class_name annot_string) + threadsafe_annotations && match annot.Annot.parameters with | ["false"] -> false | _ -> true in diff --git a/infer/src/checkers/ThreadSafetyConfig.ml b/infer/src/checkers/ThreadSafetyConfig.ml new file mode 100644 index 000000000..823fdacae --- /dev/null +++ b/infer/src/checkers/ThreadSafetyConfig.ml @@ -0,0 +1,19 @@ +(* + * Copyright (c) 2017 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + *) + +open! IStd + +module F = Format + +module AnnotationAliases = struct + + let of_json = function + | `List aliases -> List.map ~f:Yojson.Basic.Util.to_string aliases + | _ -> failwith "Couldn't parse thread-safety annotation aliases; expected list of strings" +end diff --git a/infer/src/checkers/ThreadSafetyConfig.mli b/infer/src/checkers/ThreadSafetyConfig.mli new file mode 100644 index 000000000..363653e19 --- /dev/null +++ b/infer/src/checkers/ThreadSafetyConfig.mli @@ -0,0 +1,18 @@ +(* + * Copyright (c) 2017 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + *) + +open! IStd + +module F = Format + +(** List of annotations that should be considered aliases of @ThreadSafe *) +module AnnotationAliases : sig + + val of_json : Yojson.Basic.json -> string list +end diff --git a/infer/tests/codetoanalyze/java/threadsafety/.inferconfig b/infer/tests/codetoanalyze/java/threadsafety/.inferconfig new file mode 100644 index 000000000..be9c7530b --- /dev/null +++ b/infer/tests/codetoanalyze/java/threadsafety/.inferconfig @@ -0,0 +1,3 @@ +{ + "threadsafe-aliases": ["MyThreadSafeAlias1", "codetoanalyze.java.checkers.MyThreadSafeAlias2"] +} diff --git a/infer/tests/codetoanalyze/java/threadsafety/Annotations.java b/infer/tests/codetoanalyze/java/threadsafety/Annotations.java index b940b26d8..9a4d26553 100644 --- a/infer/tests/codetoanalyze/java/threadsafety/Annotations.java +++ b/infer/tests/codetoanalyze/java/threadsafety/Annotations.java @@ -48,6 +48,16 @@ import com.facebook.infer.annotation.ReturnsOwnership; @interface OnUnmount { } +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.CLASS) +@interface MyThreadSafeAlias1 { +} + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.CLASS) +@interface MyThreadSafeAlias2 { +} + interface Interface { @Functional Object functionalMethod(); @@ -64,6 +74,21 @@ class AssumedThreadSafe { } } +// this annotation is defined as an alias for @ThreadSafe in .inferconfig +class ThreadSafeAlias { + Object field; + + @MyThreadSafeAlias1 + void threadSafeAliasBad1() { + this.field = new Object(); + } + + @MyThreadSafeAlias2 + void threadSafeAliasBad2() { + this.field = new Object(); + } +} + @ThreadSafe class Annotations implements Interface { Object f; diff --git a/infer/tests/codetoanalyze/java/threadsafety/issues.exp b/infer/tests/codetoanalyze/java/threadsafety/issues.exp index ddd738682..40910a6e1 100644 --- a/infer/tests/codetoanalyze/java/threadsafety/issues.exp +++ b/infer/tests/codetoanalyze/java/threadsafety/issues.exp @@ -7,6 +7,8 @@ codetoanalyze/java/threadsafety/Annotations.java, long Annotations.functionaLong codetoanalyze/java/threadsafety/Annotations.java, void Annotations.functionalAndNonfunctionalBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.Annotations.mInt] codetoanalyze/java/threadsafety/Annotations.java, void Annotations.mutateOffUiThreadBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.Annotations.f] codetoanalyze/java/threadsafety/Annotations.java, void Annotations.mutateSubfieldOfConfinedBad(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.Annotations.encapsulatedField.codetoanalyze.java.checkers.Obj.f] +codetoanalyze/java/threadsafety/Annotations.java, void ThreadSafeAlias.threadSafeAliasBad1(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeAlias.field] +codetoanalyze/java/threadsafety/Annotations.java, void ThreadSafeAlias.threadSafeAliasBad2(), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.ThreadSafeAlias.field] codetoanalyze/java/threadsafety/Builders.java, Builders$Obj Builders.buildThenMutateBad(Builders$Obj), 3, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.Builders$Obj.g] codetoanalyze/java/threadsafety/Builders.java, Builders$Obj Builders.mutateBad(Builders$Obj), 1, THREAD_SAFETY_VIOLATION, [access to codetoanalyze.java.checkers.Builders$Obj.g] codetoanalyze/java/threadsafety/Constructors.java, Constructors Constructors.singletonBad(), 2, THREAD_SAFETY_VIOLATION, [call to Constructors.(Object),access to Constructors.staticField]