Skip to content

Commit

Permalink
[transitive access] look for annotations in parent classes too
Browse files Browse the repository at this point in the history
Summary:
This matches the behaviour of the annotation reachability checker and
seems like a good idea.

Reviewed By: hajduakos

Differential Revision: D67276563

fbshipit-source-id: 6d550f3c125ab6f3c18a59add0e8aeef2293f85c
  • Loading branch information
jvillard authored and facebook-github-bot committed Dec 17, 2024
1 parent 69f58e4 commit 141eb33
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 13 deletions.
17 changes: 10 additions & 7 deletions infer/src/pulse/PulseTransitiveAccessChecker.ml
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,15 @@ end = struct
List.exists fieldnames_to_monitor ~f:(String.equal (Fieldname.get_field_name fieldname))


let procname_has_annotation procname annotations =
let match_one_annotation anno =
let has_annot ia = Annotations.ia_ends_with ia anno in
Annotations.pname_has_return_annot procname has_annot
let proc_name_has_annotation tenv proc_name annotations =
let match_one_annotation proc_name annotation =
let has_annot ia = Annotations.ia_ends_with ia annotation in
Annotations.pname_has_return_annot proc_name has_annot
in
List.exists annotations ~f:match_one_annotation
PatternMatch.override_exists
(fun proc_name ->
List.exists annotations ~f:(fun annot -> match_one_annotation proc_name annot) )
tenv proc_name


let procname_is_matched specs tenv procname =
Expand Down Expand Up @@ -114,7 +117,7 @@ end = struct
List.mem ~equal:String.equal mn method_name )
&& map_or_true class_name_regex ~f:match_class_name_regex
&& map_or_true method_name_regex ~f:match_method_name_regex
&& map_or_true annotations ~f:(procname_has_annotation procname)
&& map_or_true annotations ~f:(proc_name_has_annotation tenv procname)
in
List.exists specs ~f:check_one_procname_spec

Expand Down Expand Up @@ -184,7 +187,7 @@ end = struct
&& map_or_true initial_caller_class_does_not_extend
~f:(check_not_extends tenv procname final_class_only)
&& map_or_true procedures ~f:(fun specs -> procname_is_matched specs tenv procname)
&& map_or_true annotations ~f:(procname_has_annotation procname)
&& map_or_true annotations ~f:(proc_name_has_annotation tenv procname)


type context_metadata = {description: string; tag: string}
Expand Down
19 changes: 18 additions & 1 deletion infer/tests/codetoanalyze/java/pulse/TransitiveAccess.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ public static void sink_if_arg_true(boolean arg) {
}
}

abstract class BaseSinks {
@SinkAnno
public abstract void overrideAnnotated();
}

abstract class ChildSinks extends BaseSinks {
public void overrideAnnotated() {}
}

public static class Base {}

public static class Context extends Base {
Expand Down Expand Up @@ -97,7 +106,15 @@ public static void sourceCallsFuncWithAnnoBad() {
Sinks.funcWithAnno();
}

public static void sourceCallsFuncWithAnnoOk() {
public void sourceCallsOverrideAnnotatedBad(ChildSinks sink) {
sink.overrideAnnotated();
}

public void sourceCallsAbstractOverrideAnnotatedBad(BaseSinks sink) {
sink.overrideAnnotated();
}

public static void sourceCallsSafeWithAnnoOk() {
Sinks.safeWithAnno();
}
}
Expand Down
12 changes: 7 additions & 5 deletions infer/tests/codetoanalyze/java/pulse/issues.exp
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,17 @@ codetoanalyze/java/pulse/TextUtilsExample.java, TextUtilsExample.testTextUtilsIs
codetoanalyze/java/pulse/TextUtilsExample.java, TextUtilsExample.testTextUtilsIsEmptyNullBad():void, 4, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is assigned to the null pointer,assigned,invalid access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.sourceBad():void, 1, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.sourceConditionalBad():void, 1, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess$Sinks.sink_if_arg_true(boolean)` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.access_codetoanalyze.java.infer.TransitiveAccess$Context$Lambda$_13_0():void, 0, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess$Context.lambda$sourceWithLambdaBad$1()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.access_codetoanalyze.java.infer.TransitiveAccess$Context$Lambda$_15_0():void, 0, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess$Context.lambda$sourceWithLambdaBad$1()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.lambda$sourceWithLambdaBad$1():void, 0, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.sourceWithLambdaBad():void, 2, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess$Context$Lambda$_13_0.call()` here,when calling `void TransitiveAccess$Context.access_codetoanalyze.java.infer.TransitiveAccess$Context$Lambda$_13_0()` here,when calling `void TransitiveAccess$Context.lambda$sourceWithLambdaBad$1()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.access_codetoanalyze.java.infer.TransitiveAccess$Context$Lambda$_16_0():void, 0, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess$Context.lambda$sourceWithLambdaNoCallBad$2()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.sourceWithLambdaBad():void, 2, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess$Context$Lambda$_15_0.call()` here,when calling `void TransitiveAccess$Context.access_codetoanalyze.java.infer.TransitiveAccess$Context$Lambda$_15_0()` here,when calling `void TransitiveAccess$Context.lambda$sourceWithLambdaBad$1()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.access_codetoanalyze.java.infer.TransitiveAccess$Context$Lambda$_18_0():void, 0, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess$Context.lambda$sourceWithLambdaNoCallBad$2()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.lambda$sourceWithLambdaNoCallBad$2():void, 0, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.access_codetoanalyze.java.infer.TransitiveAccess$Context$Lambda$_14_0():void, 0, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess$Context.lambda$sourceWithLambdaIndirectBad$4()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.sourceWithLambdaIndirectBad():void, 1, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess.caller(TransitiveAccess$Callback)` here,when calling `void TransitiveAccess$Context$Lambda$_14_0.call()` here,when calling `void TransitiveAccess$Context.access_codetoanalyze.java.infer.TransitiveAccess$Context$Lambda$_14_0()` here,when calling `void TransitiveAccess$Context.lambda$sourceWithLambdaIndirectBad$4()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.access_codetoanalyze.java.infer.TransitiveAccess$Context$Lambda$_16_0():void, 0, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess$Context.lambda$sourceWithLambdaIndirectBad$4()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.sourceWithLambdaIndirectBad():void, 1, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess.caller(TransitiveAccess$Callback)` here,when calling `void TransitiveAccess$Context$Lambda$_16_0.call()` here,when calling `void TransitiveAccess$Context.access_codetoanalyze.java.infer.TransitiveAccess$Context$Lambda$_16_0()` here,when calling `void TransitiveAccess$Context.lambda$sourceWithLambdaIndirectBad$4()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.lambda$sourceWithLambdaIndirectBad$4():void, 0, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.sourceCallsFuncWithAnnoBad():void, 1, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.sourceCallsOverrideAnnotatedBad(codetoanalyze.java.infer.TransitiveAccess$ChildSinks):void, 1, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess$Context.sourceCallsAbstractOverrideAnnotatedBad(codetoanalyze.java.infer.TransitiveAccess$BaseSinks):void, 1, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess.sourceWithAnnoBad():void, 1, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess.sourceWithAnnoAndLambdaBad():void, 1, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess.caller(TransitiveAccess$Callback)` here,when calling `void TransitiveAccess$Lambda$_9_0.call()` here,when calling `void TransitiveAccess.access_codetoanalyze.java.infer.TransitiveAccess$Lambda$_9_0()` here,when calling `void TransitiveAccess.lambda$sourceWithAnnoAndLambdaBad$0()` here,access occurs here]
codetoanalyze/java/pulse/TransitiveAccess.java, codetoanalyze.java.infer.TransitiveAccess.sourceWithChainOfCallsBad():void, 1, PULSE_TRANSITIVE_ACCESS, no_bucket, ERROR, [when calling `void TransitiveAccess.f1()` here,when calling `void TransitiveAccess.f2()` here,when calling `void TransitiveAccess.f3()` here,access occurs here]
Expand Down

0 comments on commit 141eb33

Please sign in to comment.