From 990d0fbed5f6686e6710347270f61b3545203157 Mon Sep 17 00:00:00 2001 From: Nikos Gorogiannis Date: Fri, 4 Jun 2021 02:01:10 -0700 Subject: [PATCH] [racerd] treat @Initializer methods as constructors wrt ownership Summary: `Initializer` is used (mostly by Nullsafe) to signal that a method will only be run from/as a constructor, even if public. RacerD should recognise this annotation; this diff makes RacerD treat methods annotated as `Initializer` like constructors with regards to the ownership of the receiver object. Reviewed By: skcho Differential Revision: D28748068 fbshipit-source-id: 5dd060865 --- infer/src/concurrency/RacerDModels.ml | 6 +++- .../java/racerd/Annotations.java | 12 ++++++++ .../codetoanalyze/java/racerd/issues.exp | 28 +++++++++---------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/infer/src/concurrency/RacerDModels.ml b/infer/src/concurrency/RacerDModels.ml index 0be755fd1..be6a20985 100644 --- a/infer/src/concurrency/RacerDModels.ml +++ b/infer/src/concurrency/RacerDModels.ml @@ -572,7 +572,11 @@ let is_synchronized_container callee_pname (access_exp : HilExp.AccessExpression let is_initializer tenv proc_name = - Procname.is_constructor proc_name || FbThreadSafety.is_custom_init tenv proc_name + Procname.is_constructor proc_name + || FbThreadSafety.is_custom_init tenv proc_name + || PatternMatch.override_exists + (fun pname -> Annotations.pname_has_return_annot pname Annotations.ia_is_initializer) + tenv proc_name let get_current_class_and_superclasses_satisfying_attr_check check tenv pname = diff --git a/infer/tests/codetoanalyze/java/racerd/Annotations.java b/infer/tests/codetoanalyze/java/racerd/Annotations.java index 783f14180..7a061d428 100644 --- a/infer/tests/codetoanalyze/java/racerd/Annotations.java +++ b/infer/tests/codetoanalyze/java/racerd/Annotations.java @@ -9,6 +9,7 @@ package codetoanalyze.java.checkers; import android.support.annotation.UiThread; import com.facebook.infer.annotation.Functional; +import com.facebook.infer.annotation.Initializer; import com.facebook.infer.annotation.ReturnsOwnership; import com.facebook.infer.annotation.SynchronizedCollection; import com.facebook.infer.annotation.ThreadConfined; @@ -412,6 +413,17 @@ class Annotations implements Interface { public void injectPropOk(@InjectProp Obj o) { o.f = 7; } + + Object onlyUpdatedInInitializer; + + @Initializer + public void setOnlyUpdatedInInitializerOk(Object o) { + onlyUpdatedInInitializer = o; + } + + public synchronized Object getOnlyUpdatedInInitializerOk() { + return onlyUpdatedInInitializer; + } } @UiThread diff --git a/infer/tests/codetoanalyze/java/racerd/issues.exp b/infer/tests/codetoanalyze/java/racerd/issues.exp index c3da86f38..38abd32e5 100644 --- a/infer/tests/codetoanalyze/java/racerd/issues.exp +++ b/infer/tests/codetoanalyze/java/racerd/issues.exp @@ -1,18 +1,18 @@ codetoanalyze/java/racerd/AndroidModels.java, codetoanalyze.java.checkers.AndroidModels.someResourceMethodsNotFunctionalBad():void, 63, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mField`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.FP_functionalAcrossBoxingLongOk():int, 342, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mBoxedLong2`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.FP_functionalAcrossUnboxingOk():boolean, 312, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mBool2`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.conditional2_bad(boolean):void, 180, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.ii`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.functionaLongBad():long, 286, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mLong`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.functionalAcrossUnboxingLongBad():int, 333, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mLong2`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.functionalAndNonfunctionalBad():void, 378, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mInt`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.functionalDoubleBad():double, 278, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mDouble`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.mutateOffUiThreadBad():void, 106, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.f`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.mutateSubfieldOfConfinedBad():void, 146, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.encapsulatedField.f`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.read_from_non_confined_method_Bad():void, 159, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [,access to `this.zz`,,access to `this.zz`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.read_off_UI_thread_Bad():void, 190, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [,access to `this.f`,,access to `this.f`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.ThreadSafeAlias.threadSafeAliasBad1():void, 82, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.field`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.ThreadSafeAlias.threadSafeAliasBad2():void, 87, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.field`] -codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.WeirdAnnotation.fooBad():void, 454, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.f`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.FP_functionalAcrossBoxingLongOk():int, 343, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mBoxedLong2`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.FP_functionalAcrossUnboxingOk():boolean, 313, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mBool2`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.conditional2_bad(boolean):void, 181, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.ii`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.functionaLongBad():long, 287, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mLong`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.functionalAcrossUnboxingLongBad():int, 334, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mLong2`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.functionalAndNonfunctionalBad():void, 379, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mInt`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.functionalDoubleBad():double, 279, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.mDouble`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.mutateOffUiThreadBad():void, 107, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.f`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.mutateSubfieldOfConfinedBad():void, 147, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.encapsulatedField.f`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.read_from_non_confined_method_Bad():void, 160, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [,access to `this.zz`,,access to `this.zz`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.Annotations.read_off_UI_thread_Bad():void, 191, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [,access to `this.f`,,access to `this.f`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.ThreadSafeAlias.threadSafeAliasBad1():void, 83, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.field`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.ThreadSafeAlias.threadSafeAliasBad2():void, 88, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.field`] +codetoanalyze/java/racerd/Annotations.java, codetoanalyze.java.checkers.WeirdAnnotation.fooBad():void, 466, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.f`] codetoanalyze/java/racerd/Arrays.java, Arrays.arrayParameterWriteBad(int[]):void, 26, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `name1.[_]`] codetoanalyze/java/racerd/Arrays.java, Arrays.readWriteRaceBad(java.lang.String):java.lang.String, 47, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [,access to `this.strArr1.[_]`,,access to `this.strArr1.[_]`] codetoanalyze/java/racerd/Arrays.java, Arrays.writeWriteRaceBad(java.lang.String):void, 39, THREAD_SAFETY_VIOLATION, no_bucket, WARNING, [access to `this.strArr1.[_]`]