Skip to content

Commit

Permalink
[annot] Support Erlang
Browse files Browse the repository at this point in the history
Summary: Add support for Erlang. Wait -- Erlang doesn't have annotations. That's right. But annotation reachability also supports regexps to model methods as if they were annotated, so we can use this checker for callgraph reachability in general.

Reviewed By: mmarescotti

Differential Revision: D65213665

fbshipit-source-id: 4d7d97b982182d9831a6069edcd682f41452ddbb
  • Loading branch information
hajduakos authored and facebook-github-bot committed Oct 30, 2024
1 parent 249de1f commit 8566303
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 18 deletions.
6 changes: 4 additions & 2 deletions infer/man/man1/infer-analyze.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ OPTIONS
indirectly, another method annotated with `@B`. Besides the custom
pairs, it is also possible to enable some built-in checks, such as
`@PerformanceCritical` reaching `@Expensive` or `@NoAllocation`
reaching `new`. See flags starting with
`--annotation-reachability`. (Conversely:
reaching `new`. It is also possible to model methods as if they
were annotated, using regular expressions. This should also work
in languages where there are no annotations. See flags starting
with `--annotation-reachability`. (Conversely:
--no-annotation-reachability)

--annotation-reachability-only
Expand Down
6 changes: 4 additions & 2 deletions infer/man/man1/infer-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ OPTIONS
indirectly, another method annotated with `@B`. Besides the custom
pairs, it is also possible to enable some built-in checks, such as
`@PerformanceCritical` reaching `@Expensive` or `@NoAllocation`
reaching `new`. See flags starting with
`--annotation-reachability`. (Conversely:
reaching `new`. It is also possible to model methods as if they
were annotated, using regular expressions. This should also work
in languages where there are no annotations. See flags starting
with `--annotation-reachability`. (Conversely:
--no-annotation-reachability)
See also infer-analyze(1).

Expand Down
6 changes: 4 additions & 2 deletions infer/man/man1/infer.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ OPTIONS
indirectly, another method annotated with `@B`. Besides the custom
pairs, it is also possible to enable some built-in checks, such as
`@PerformanceCritical` reaching `@Expensive` or `@NoAllocation`
reaching `new`. See flags starting with
`--annotation-reachability`. (Conversely:
reaching `new`. It is also possible to model methods as if they
were annotated, using regular expressions. This should also work
in languages where there are no annotations. See flags starting
with `--annotation-reachability`. (Conversely:
--no-annotation-reachability)
See also infer-analyze(1).

Expand Down
2 changes: 1 addition & 1 deletion infer/src/backend/registerCheckers.ml
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ let all_checkers =
(let annot_reach =
interprocedural Payloads.Fields.annot_map AnnotationReachability.checker
in
[(annot_reach, Java); (annot_reach, Clang)] ) }
[(annot_reach, Erlang); (annot_reach, Java)] ) }
; { checker= ConfigImpactAnalysis
; callbacks=
(let checker =
Expand Down
6 changes: 4 additions & 2 deletions infer/src/base/Checker.ml
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,15 @@ let config_unsafe checker =
| AnnotationReachability ->
{ id= "annotation-reachability"
; kind= UserFacing {title= "Annotation Reachability"; markdown_body= ""}
; support= mk_support_func ~java:Support ()
; support= mk_support_func ~erlang:Support ~java:Support ()
; short_documentation=
"Given pairs of source and sink annotations, e.g. `@A` and `@B`, this checker will warn \
whenever some method annotated with `@A` calls, directly or indirectly, another method \
annotated with `@B`. Besides the custom pairs, it is also possible to enable some \
built-in checks, such as `@PerformanceCritical` reaching `@Expensive` or \
`@NoAllocation` reaching `new`. See flags starting with `--annotation-reachability`."
`@NoAllocation` reaching `new`. It is also possible to model methods as if they were \
annotated, using regular expressions. This should also work in languages where there \
are no annotations. See flags starting with `--annotation-reachability`."
; cli_flags= Some {deprecated= []; show_in_help= true}
; enabled_by_default= false
; activates= [] }
Expand Down
24 changes: 15 additions & 9 deletions infer/src/checkers/annotationReachability.ml
Original file line number Diff line number Diff line change
Expand Up @@ -93,18 +93,24 @@ let parse_custom_models () =


let check_attributes check tenv pname =
let proc_has_attribute = Annotations.pname_has_return_annot pname check in
let class_has_attribute =
( if Config.annotation_reachability_apply_superclass_annotations then
PatternMatch.Java.check_class_attributes
else PatternMatch.Java.check_current_class_attributes )
check tenv pname
in
class_has_attribute || proc_has_attribute
match pname with
| Procname.Java _ ->
let proc_has_attribute = Annotations.pname_has_return_annot pname check in
let class_has_attribute =
( if Config.annotation_reachability_apply_superclass_annotations then
PatternMatch.Java.check_class_attributes
else PatternMatch.Java.check_current_class_attributes )
check tenv pname
in
class_has_attribute || proc_has_attribute
| _ ->
false


let check_modeled_annotation models annot pname =
let method_name = Procname.to_string ~verbosity:FullNameOnly pname in
let method_name =
Procname.to_string ~verbosity:(if Procname.is_erlang pname then Verbose else FullNameOnly) pname
in
Option.exists (String.Map.find models annot.Annot.class_name) ~f:(fun methods ->
List.exists methods ~f:(fun r -> Str.string_match r method_name 0) )

Expand Down
15 changes: 15 additions & 0 deletions infer/tests/codetoanalyze/erlang/annotreach/.inferconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"annotation-reachability": true,
"annotation-reachability-custom-pairs": [
{
"sources": ["Source"],
"sinks": ["Sink"],
"sanitizers": ["Sanitizer"]
}
],
"annotation-reachability-custom-models": {
"Source": [".*:.*source.*/0"],
"Sink": [".*:.*sink.*/0"],
"Sanitizer": [".*:.*sanitizer.*/0"]
}
}
18 changes: 18 additions & 0 deletions infer/tests/codetoanalyze/erlang/annotreach/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

TESTS_DIR = ../../..

INFER_OPTIONS = \
--annotation-reachability-only --debug-exceptions \
--project-root $(TESTS_DIR) --print-types

INFERPRINT_OPTIONS = --issues-tests

SOURCES = $(wildcard *.erl)

include $(TESTS_DIR)/erlc.make

infer-out/report.json: $(MAKEFILE_LIST)
2 changes: 2 additions & 0 deletions infer/tests/codetoanalyze/erlang/annotreach/issues.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
codetoanalyze/erlang/annotreach/reach.erl, test_source2_Bad/0, 0, CHECKERS_ANNOTATION_REACHABILITY_ERROR, no_bucket, ERROR, [Method test_source2_Bad/0, marked as source @Source,calls sink/0,sink/0 defined here, marked as sink @Sink]
codetoanalyze/erlang/annotreach/reach.erl, test_source4_Bad/0, 0, CHECKERS_ANNOTATION_REACHABILITY_ERROR, no_bucket, ERROR, [Method test_source4_Bad/0, marked as source @Source,calls not_sani_tizer/0,not_sani_tizer/0 defined here,calls sink/0,sink/0 defined here, marked as sink @Sink]
33 changes: 33 additions & 0 deletions infer/tests/codetoanalyze/erlang/annotreach/reach.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
% Copyright (c) Facebook, Inc. and its affiliates.
%
% This source code is licensed under the MIT license found in the
% LICENSE file in the root directory of this source tree.

-module(reach).

-export([
test_source1_Ok/0,
test_source2_Bad/0,
test_source3_Ok/0,
test_source4_Bad/0, test_source5_Ok/0
]).

sink() -> ok.

not_si_nk() -> ok.

not_sink_because_arity(X) -> X.

sanitizer() -> sink().

not_sani_tizer() -> sink().

test_source1_Ok() -> not_si_nk().

test_source2_Bad() -> sink().

test_source3_Ok() -> sanitizer().

test_source4_Bad() -> not_sani_tizer().

test_source5_Ok() -> not_sink_because_arity(1).

0 comments on commit 8566303

Please sign in to comment.