diff --git a/infer/man/man1/infer-analyze.txt b/infer/man/man1/infer-analyze.txt index 9fdcc4a86..dd6dbb4bc 100644 --- a/infer/man/man1/infer-analyze.txt +++ b/infer/man/man1/infer-analyze.txt @@ -372,6 +372,10 @@ QUANDARY CHECKER OPTIONS --quandary-sources json Specify custom sources for Quandary (default: []) RACERD CHECKER OPTIONS + --racerd-guardedby + Activates: Check @GuardedBy annotations with RacerD (Conversely: + --no-racerd-guardedby) + --threadsafe-aliases json Specify custom annotations that should be considered aliases of @ThreadSafe (default: []) diff --git a/infer/man/man1/infer-full.txt b/infer/man/man1/infer-full.txt index 4b411f1a6..43b24784b 100644 --- a/infer/man/man1/infer-full.txt +++ b/infer/man/man1/infer-full.txt @@ -727,6 +727,10 @@ OPTIONS Deactivates: the RacerD thread safety analysis (Conversely: --racerd) See also infer-analyze(1). + --racerd-guardedby + Activates: Check @GuardedBy annotations with RacerD (Conversely: + --no-racerd-guardedby) See also infer-analyze(1). + --racerd-only Activates: Enable --racerd and disable all other checkers (Conversely: --no-racerd-only) See also infer-analyze(1). diff --git a/infer/man/man1/infer.txt b/infer/man/man1/infer.txt index 5a5dc3bbd..811dc89af 100644 --- a/infer/man/man1/infer.txt +++ b/infer/man/man1/infer.txt @@ -727,6 +727,10 @@ OPTIONS Deactivates: the RacerD thread safety analysis (Conversely: --racerd) See also infer-analyze(1). + --racerd-guardedby + Activates: Check @GuardedBy annotations with RacerD (Conversely: + --no-racerd-guardedby) See also infer-analyze(1). + --racerd-only Activates: Enable --racerd and disable all other checkers (Conversely: --no-racerd-only) See also infer-analyze(1). diff --git a/infer/src/base/Config.ml b/infer/src/base/Config.ml index 48611c084..e1f40d486 100644 --- a/infer/src/base/Config.ml +++ b/infer/src/base/Config.ml @@ -1859,6 +1859,12 @@ and quiet = "Do not print specs on standard output (default: only print for the $(b,report) command)" +and racerd_guardedby = + CLOpt.mk_bool ~long:"racerd-guardedby" ~default:false + ~in_help:InferCommand.[(Analyze, manual_racerd)] + "Check @GuardedBy annotations with RacerD" + + and reactive = CLOpt.mk_bool ~deprecated:["reactive"] ~long:"reactive" ~short:'r' ~in_help:InferCommand.[(Analyze, manual_generic)] @@ -2885,6 +2891,8 @@ and quiet = !quiet and racerd = !racerd +and racerd_guardedby = !racerd_guardedby + and reactive_mode = !reactive || InferCommand.(equal Diff) command and reactive_capture = !reactive_capture diff --git a/infer/src/base/Config.mli b/infer/src/base/Config.mli index f392a9328..137ff7046 100644 --- a/infer/src/base/Config.mli +++ b/infer/src/base/Config.mli @@ -69,20 +69,10 @@ val classnames_dir_name : string val classpath : string option -val class_loads : bool - -val class_loads_roots : String.Set.t - val costs_report_json : string val cpp_extra_include_dir : string -val driver_stats_dir_name : string - -val duplicates_filename : string - -val relative_cpp_models_dir : string - val csl_analysis : bool val default_failure_name : string @@ -91,10 +81,14 @@ val default_in_zip_results_dir : string val dotty_output : string -val events_dir_name : string +val driver_stats_dir_name : string + +val duplicates_filename : string val etc_dir : string +val events_dir_name : string + val fail_on_issue_exit_code : int val frontend_stats_dir_name : string @@ -155,6 +149,8 @@ val property_attributes : string val racerd_issues_dir_name : string +val relative_cpp_models_dir : string + val relative_path_backtrack : int val report : bool @@ -179,10 +175,10 @@ val smt_output : bool val source_file_extentions : string list -val sources : string list - val sourcepath : string option +val sources : string list + val specs_dir_name : string val specs_files_suffix : string @@ -201,17 +197,15 @@ val use_cost_threshold : bool val weak : string -val whitelisted_cpp_methods : string list - val whitelisted_cpp_classes : string list +val whitelisted_cpp_methods : string list + val wrappers_dir : string (** {2 Configuration values specified by command-line options} *) -val anon_args : string list - -val rest : string list +type iphoneos_target_sdk_version_path_regex = {path: Str.regexp; version: string} val abs_struct : int @@ -219,11 +213,11 @@ val abs_val : int val allow_leak : bool -val analysis_path_regex_whitelist : string list +val analysis_blacklist_files_containing : string list val analysis_path_regex_blacklist : string list -val analysis_blacklist_files_containing : string list +val analysis_path_regex_whitelist : string list val analysis_stops : bool @@ -233,16 +227,18 @@ val annotation_reachability : bool val annotation_reachability_custom_pairs : Yojson.Basic.json +val anon_args : string list + val array_level : int val biabduction : bool -val bootclasspath : string option - val bo_debug : int val bo_relational_domain : [`Bo_relational_domain_oct | `Bo_relational_domain_poly] option +val bootclasspath : string option + val buck : bool val buck_blacklist : string list @@ -268,8 +264,6 @@ val captured_dir : string val changed_files_index : string option -val nullsafe : bool - val check_version : string option val clang_biniou_file : string option @@ -282,6 +276,10 @@ val clang_ignore_regex : string option val clang_include_to_override_regex : string option +val class_loads : bool + +val class_loads_roots : String.Set.t + val command : InferCommand.t val compute_analytics : bool @@ -304,6 +302,8 @@ val cxx_infer_headers : bool val cxx_scope_guards : Yojson.Basic.json +val debug_exceptions : bool + val debug_level_analysis : int val debug_level_capture : int @@ -312,8 +312,6 @@ val debug_level_linters : int val debug_level_test_determinator : int -val debug_exceptions : bool - val debug_mode : bool val default_linters : bool @@ -336,6 +334,8 @@ val eradicate : bool val eradicate_condition_redundant : bool +val eradicate_debug : bool + val eradicate_field_not_mutable : bool val eradicate_field_over_annotated : bool @@ -344,8 +344,6 @@ val eradicate_optional_present : bool val eradicate_return_over_annotated : bool -val eradicate_debug : bool - val eradicate_verbose : bool val fail_on_bug : bool @@ -366,16 +364,16 @@ val flavors : bool val force_delete_results_dir : bool -val fragment_retains_view : bool - val force_integration : build_system option -val from_json_report : string option +val fragment_retains_view : bool -val frontend_tests : bool +val from_json_report : string option val frontend_stats : bool +val frontend_tests : bool + val function_pointer_specialization : bool val gen_previous_build_command_script : string option @@ -384,10 +382,10 @@ val generated_classes : string option val get_linter_doc_url : linter_id:string -> string option -val html : bool - val hoisting_report_only_expensive : bool +val html : bool + val icfg_dotty_outfile : string option val immutable_cast : bool @@ -400,8 +398,6 @@ val inferconfig_file : string option val iphoneos_target_sdk_version : string option -type iphoneos_target_sdk_version_path_regex = {path: Str.regexp; version: string} - val iphoneos_target_sdk_version_path_regex : iphoneos_target_sdk_version_path_regex list val issues_fields : @@ -465,20 +461,18 @@ val log_file : string val log_skipped : bool -val perf_profiler_data_file : string option - val loop_hoisting : bool val max_nesting : int option -val method_decls_info : string option - val memcached : bool val memcached_size_mb : int val merge : bool +val method_decls_info : string option + val ml_buckets : [`MLeak_all | `MLeak_arc | `MLeak_cf | `MLeak_cpp | `MLeak_no_arc | `MLeak_unknown] list @@ -496,6 +490,8 @@ val no_translate_libs : bool val nullable_annotation : string option +val nullsafe : bool + val nullsafe_strict_containers : bool val only_cheap_debug : bool @@ -506,6 +502,8 @@ val only_show : bool val ownership : bool +val perf_profiler_data_file : string option + val pmd_xml : bool val precondition_stats : bool @@ -540,10 +538,12 @@ val procedures_source_file : bool val procs_csv : string option -val project_root : string +val profiler_samples : string option val progress_bar : [`MultiLine | `Plain | `Quiet] +val project_root : string + val pulse : bool val pulse_max_disjuncts : int @@ -554,22 +554,26 @@ val purity : bool val quandary : bool -val quandaryBO : bool - val quandary_endpoints : Yojson.Basic.json val quandary_sanitizers : Yojson.Basic.json +val quandary_sinks : Yojson.Basic.json + val quandary_sources : Yojson.Basic.json -val quandary_sinks : Yojson.Basic.json +val quandaryBO : bool val quiet : bool -val reactive_mode : bool +val racerd : bool + +val racerd_guardedby : bool val reactive_capture : bool +val reactive_mode : bool + val reanalyze : bool val report_current : string option @@ -580,12 +584,12 @@ val report_hook : string option val report_previous : string option -val tracing : bool - val reports_include_ml_loc : bool val resource_leak : bool +val rest : string list + val results_dir : string val seconds_per_iteration : float option @@ -614,11 +618,11 @@ val source_files_cfg : bool val source_files_filter : string option -val source_files_type_environment : bool +val source_files_freshly_captured : bool val source_files_procedure_names : bool -val source_files_freshly_captured : bool +val source_files_type_environment : bool val source_preview : bool @@ -646,12 +650,8 @@ val test_determinator : bool val test_filtering : bool -val profiler_samples : string option - val testing_mode : bool -val racerd : bool - val threadsafe_aliases : Yojson.Basic.json val topl_properties : string list @@ -660,12 +660,14 @@ val trace_error : bool val trace_events : bool -val trace_ondemand : bool - val trace_join : bool +val trace_ondemand : bool + val trace_rearrange : bool +val tracing : bool + val tv_commit : string option val tv_limit : int @@ -691,7 +693,6 @@ val write_html_whitelist_regex : string list val xcode_developer_dir : string option val xcpretty : bool - (** {2 Global variables with initial values specified by command-line options} *) val clang_compilation_dbs : [`Escaped of string | `Raw of string] list ref @@ -702,11 +703,11 @@ val print_usage_exit : unit -> 'a (** {2 Miscellanous} *) +val is_in_custom_symbols : string -> string -> bool +(** Does named symbol match any prefix in the named custom symbol list? *) + val java_package_is_external : string -> bool (** Check if a Java package is external to the repository *) val quandaryBO_filtered_issues : IssueType.t list (** List of issues that are enabled by QuandaryBO but should not be in the final report.json *) - -val is_in_custom_symbols : string -> string -> bool -(** Does named symbol match any prefix in the named custom symbol list? *) diff --git a/infer/src/concurrency/RacerD.ml b/infer/src/concurrency/RacerD.ml index dff19c491..85e93655d 100644 --- a/infer/src/concurrency/RacerD.ml +++ b/infer/src/concurrency/RacerD.ml @@ -1113,12 +1113,14 @@ let report_unsafe_accesses classname (aggregated_access_map : ReportMap.t) = else List.fold reportable_accesses ~init ~f:(report_unsafe_access reportable_accesses) in let report_guardedby_violations_on_location grouped_accesses init = - List.fold grouped_accesses ~init ~f:(fun acc r -> - if should_report_guardedby_violation classname r && not (is_duplicate_report r acc) then ( - report_thread_safety_violation ~make_description:make_guardedby_violation_description - ~report_kind:GuardedByViolation r ; - update_reported r acc ) - else acc ) + if Config.racerd_guardedby then + List.fold grouped_accesses ~init ~f:(fun acc r -> + if should_report_guardedby_violation classname r && not (is_duplicate_report r acc) then ( + report_thread_safety_violation ~make_description:make_guardedby_violation_description + ~report_kind:GuardedByViolation r ; + update_reported r acc ) + else acc ) + else init in let report grouped_accesses reported_acc = (* reset the reported reads and writes for each memory location *) diff --git a/infer/tests/build_systems/ant/issues.exp b/infer/tests/build_systems/ant/issues.exp index 39d584d37..d1c7cbfed 100644 --- a/infer/tests/build_systems/ant/issues.exp +++ b/infer/tests/build_systems/ant/issues.exp @@ -53,21 +53,17 @@ codetoanalyze/java/infer/FilterOutputStreamLeaks.java, codetoanalyze.java.infer. codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample$3.readFromInnerClassBad1():java.lang.String, 2, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure readFromInnerClassBad1()] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample$4.readFromInnerClassBad2():java.lang.String, 1, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure readFromInnerClassBad2()] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample$Sub.badSub():void, 1, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure badSub()] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample$Sub.badSub():void, 491, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.xForSub`] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.accessUnrecognizedGuardedByFieldsOk():void, 307, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.uiThread1`] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.accessUnrecognizedGuardedByFieldsOk():void, 309, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.uiThread2`] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.accessUnrecognizedGuardedByFieldsOk():void, 311, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.uiThread3`] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.accessUnrecognizedGuardedByFieldsOk():void, 313, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.nonExpression`] +codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample$Sub.badSub():void, 491, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [,access to `this.xForSub`,,access to `this.xForSub`] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.badGuardedByNormalLock():void, 1, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure badGuardedByNormalLock()] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.badGuardedByNormalLock():void, 526, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.guardedbynl`] +codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.badGuardedByNormalLock():void, 526, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [,access to `this.guardedbynl`,,access to `this.guardedbynl`] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.badGuardedByReentrantLock():void, 1, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure badGuardedByReentrantLock()] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.badGuardedByReentrantLock():void, 530, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.guardedbyrel`] +codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.badGuardedByReentrantLock():void, 530, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [,access to `this.guardedbyrel`,,access to `this.guardedbyrel`] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.byRefTrickyBad():java.lang.Object, 5, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure byRefTrickyBad()] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.byRefTrickyBad():java.lang.Object, 281, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [,access to `this.g`,,access to `this.g`] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.guardedByTypeSyntaxBad():void, 1, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure guardedByTypeSyntaxBad()] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.guardedByTypeSyntaxBad():void, 2, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure guardedByTypeSyntaxBad()] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.guardedByTypeSyntaxBad():void, 573, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.guardedByLock1`] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.guardedByTypeSyntaxBad():void, 574, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.guardedByLock2`] +codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.guardedByTypeSyntaxBad():void, 573, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [,access to `this.guardedByLock1`,,access to `this.guardedByLock1`] +codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.guardedByTypeSyntaxBad():void, 574, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [,access to `this.guardedByLock2`,,access to `this.guardedByLock2`] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.readFAfterBlockBad():void, 3, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure readFAfterBlockBad()] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.readFAfterBlockBad():void, 98, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [,access to `this.f`,,access to `this.f`] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.readFBad():void, 1, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure readFBad()] @@ -90,9 +86,9 @@ codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.Guarded codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.synchronizedOnThisBad():void, 1, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure synchronizedOnThisBad()] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.synchronizedOnThisBad():void, 205, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [,access to `infer.GuardedByExample.sGuardedByClass`,,access to `infer.GuardedByExample.sGuardedByClass`] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.writeFAfterBlockBad():void, 3, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure writeFAfterBlockBad()] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.writeFAfterBlockBad():void, 104, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.f`] +codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.writeFAfterBlockBad():void, 104, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [access to `this.f`] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.writeFBad():void, 1, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure writeFBad()] -codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.writeFBad():void, 80, GUARDEDBY_VIOLATION, no_bucket, ERROR, [access to `this.f`] +codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.writeFBad():void, 80, THREAD_SAFETY_VIOLATION, no_bucket, ERROR, [,access to `this.f`,,access to `this.f`] codetoanalyze/java/infer/GuardedByExample.java, codetoanalyze.java.infer.GuardedByExample.writeFBadWrongLock():void, 2, UNSAFE_GUARDED_BY_ACCESS, no_bucket, ERROR, [start of procedure writeFBadWrongLock()] codetoanalyze/java/infer/HashMapExample.java, codetoanalyze.java.infer.HashMapExample.getAfterClearBad():void, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure getAfterClearBad()] codetoanalyze/java/infer/HashMapExample.java, codetoanalyze.java.infer.HashMapExample.getAfterRemovingTheKeyBad():void, 5, NULL_DEREFERENCE, no_bucket, ERROR, [start of procedure getAfterRemovingTheKeyBad()] diff --git a/infer/tests/codetoanalyze/java/racerd/Makefile b/infer/tests/codetoanalyze/java/racerd/Makefile index 55dad5564..1994ac321 100644 --- a/infer/tests/codetoanalyze/java/racerd/Makefile +++ b/infer/tests/codetoanalyze/java/racerd/Makefile @@ -5,7 +5,7 @@ TESTS_DIR = ../../.. -INFER_OPTIONS = --racerd-only --debug-exceptions +INFER_OPTIONS = --racerd-only --racerd-guardedby --debug-exceptions INFERPRINT_OPTIONS = --issues-tests SOURCES = $(wildcard *.java)