From 5cdee51ed57aa40749516bf13026c930ed5432ff Mon Sep 17 00:00:00 2001 From: Sam Blackshear Date: Tue, 14 Feb 2017 12:47:01 -0800 Subject: [PATCH] [checkers] allow custom sources and sinks in annotation reachability Reviewed By: jvillard Differential Revision: D4558975 fbshipit-source-id: 5243236 --- infer/src/base/Config.ml | 8 +++ infer/src/base/Config.mli | 1 + infer/src/checkers/annotationReachability.ml | 23 ++++--- .../codetoanalyze/java/checkers/.inferconfig | 6 ++ .../java/checkers/CustomAnnotations.java | 60 +++++++++++++++++++ .../codetoanalyze/java/checkers/issues.exp | 2 + 6 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 infer/tests/codetoanalyze/java/checkers/CustomAnnotations.java diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 74cfbdc06..9bf95dea6 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -508,6 +508,13 @@ and angelic_execution = CLOpt.mk_bool ~deprecated:["angelic_execution"] ~long:"angelic-execution" ~default:true "Angelic execution, where the analysis ignores errors caused by unknown procedure calls" +and annotation_reachability = + CLOpt.mk_json ~long:"annotation-reachability" + ~parse_mode:CLOpt.(Infer [Analysis]) + "Specify custom sources/sink for the annotation reachability checker\n\ + Example format: for custom annotations com.my.annotation.{Source1,Source2,Sink1}\n\ + { \"sources\" : [\"Source1\", \"Source2\"], \"sink\" : \"Sink1\" }" + and array_level = CLOpt.mk_int ~deprecated:["arraylevel"] ~long:"array-level" ~default:0 ~meta:"int" "Level of treating the array indexing and pointer arithmetic:\n\ @@ -1439,6 +1446,7 @@ and analysis_suppress_errors_options = IList.map (fun (a, b) -> (a, !b)) analysis_suppress_errors_options and analysis_stops = !analysis_stops and angelic_execution = !angelic_execution +and annotation_reachability = !annotation_reachability and array_level = !array_level and ast_file = !ast_file and blacklist = !blacklist diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index d19b2ef94..71357d9ad 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -148,6 +148,7 @@ val analysis_stops : bool val analysis_suppress_errors : analyzer -> string list val analyzer : analyzer val angelic_execution : bool +val annotation_reachability : Yojson.Basic.json val array_level : int val ast_file : string option val blacklist : string option diff --git a/infer/src/checkers/annotationReachability.ml b/infer/src/checkers/annotationReachability.ml index 5f855fec6..cfa9aec5c 100644 --- a/infer/src/checkers/annotationReachability.ml +++ b/infer/src/checkers/annotationReachability.ml @@ -20,15 +20,24 @@ let dummy_constructor_annot = "__infer_is_constructor" let annotation_of_str annot_str = { Annot.class_name = annot_str; parameters = []; } -(* TODO: read custom source/sink pairs from user code here *) let src_snk_pairs () = + (* parse user-defined specs from .inferconfig *) + let parse_user_defined_specs = function + | `List user_specs -> + let parse_user_spec json = + let open Yojson.Basic.Util in + let sources = member "sources" json |> to_list |> List.map ~f:to_string in + let sinks = member "sink" json |> to_string in + sources, sinks in + List.map ~f:parse_user_spec user_specs + | _ -> + [] in let specs = - [ - ([Annotations.performance_critical], Annotations.expensive); - ([Annotations.no_allocation], dummy_constructor_annot); - ([Annotations.any_thread; Annotations.for_non_ui_thread], Annotations.ui_thread); - ([Annotations.ui_thread; Annotations.for_ui_thread], Annotations.for_non_ui_thread); - ] in + ([Annotations.performance_critical], Annotations.expensive) :: + ([Annotations.no_allocation], dummy_constructor_annot) :: + ([Annotations.any_thread; Annotations.for_non_ui_thread], Annotations.ui_thread) :: + ([Annotations.ui_thread; Annotations.for_ui_thread], Annotations.for_non_ui_thread) :: + (parse_user_defined_specs Config.annotation_reachability) in IList.map (fun (src_annot_str_list, snk_annot_str) -> IList.map annotation_of_str src_annot_str_list, annotation_of_str snk_annot_str) diff --git a/infer/tests/codetoanalyze/java/checkers/.inferconfig b/infer/tests/codetoanalyze/java/checkers/.inferconfig index 4a9e2d394..74b6205eb 100644 --- a/infer/tests/codetoanalyze/java/checkers/.inferconfig +++ b/infer/tests/codetoanalyze/java/checkers/.inferconfig @@ -10,5 +10,11 @@ "class": "android.view.View", "method": "findViewById" } + ], + "annotation-reachability": [ + { + "sources": ["UserDefinedSource1", "UserDefinedSource2"], + "sink": "UserDefinedSink" + } ] } diff --git a/infer/tests/codetoanalyze/java/checkers/CustomAnnotations.java b/infer/tests/codetoanalyze/java/checkers/CustomAnnotations.java new file mode 100644 index 000000000..e8e4f51e5 --- /dev/null +++ b/infer/tests/codetoanalyze/java/checkers/CustomAnnotations.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +package codetoanalyze.java.checkers; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.CLASS) +@interface UserDefinedSource1 { +} + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.CLASS) +@interface UserDefinedSource2 { +} + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.CLASS) +@interface UserDefinedSink { +} + +class CustomAnnotations { + + @UserDefinedSource1 + void source1Bad() { + sink(); + } + + @UserDefinedSource2 + void source2Bad() { + sink(); + } + + @UserDefinedSink + void sink() { + } + + @UserDefinedSource1 + void source1Ok() { + safeMethod(); + } + + @UserDefinedSource2 + void source2Ok() { + safeMethod(); + } + + void safeMethod() { + } +} diff --git a/infer/tests/codetoanalyze/java/checkers/issues.exp b/infer/tests/codetoanalyze/java/checkers/issues.exp index 03108c2d2..1b1e3f809 100644 --- a/infer/tests/codetoanalyze/java/checkers/issues.exp +++ b/infer/tests/codetoanalyze/java/checkers/issues.exp @@ -1,3 +1,5 @@ +codetoanalyze/java/checkers/CustomAnnotations.java, void CustomAnnotations.source1Bad(), 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, [] +codetoanalyze/java/checkers/CustomAnnotations.java, void CustomAnnotations.source2Bad(), 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, [] codetoanalyze/java/checkers/ExpensiveCallExample.java, View ExpensiveCallExample.callsFindViewByIdFromActivity(FragmentActivity,int), 1, CHECKERS_CALLS_EXPENSIVE_METHOD, [] codetoanalyze/java/checkers/ExpensiveCallExample.java, View ExpensiveCallExample.callsFindViewByIdFromView(ImageView,int), 1, CHECKERS_CALLS_EXPENSIVE_METHOD, [] codetoanalyze/java/checkers/ExpensiveCallExample.java, void ExpensiveCallExample.annotatedPerformanceCriticalInInterface(), 1, CHECKERS_CALLS_EXPENSIVE_METHOD, []