From d8b0c99fa15d87f4c67c891f481c65f2f99354b3 Mon Sep 17 00:00:00 2001 From: Artem Pianykh Date: Mon, 23 Mar 2020 07:44:39 -0700 Subject: [PATCH] [nullsafe] Repro for wrong nullability of $bcvarN in try-with-resource Summary: Although try-with-resource is supported by nullsafe this code pattern throws it off and make nullsafe report on a virtual **b**yte-**c**ode variable. Check out debug output from `TryWithResource` (or attached visualisation of CFG): 0. node14: $bcvar2=null (on entry to try-with-resource). 1. node16: n$14=$bcvar2, but **also** PRUNE(!(n$14 == null), true). Then we go to 2. node18: do something here and in case of exception go to 3. node25->node23->node19->node20: and here we do $bcvar2->addSuppressed(...). Because on step 1 we refined nullability of n$14, but didn't refine nullability of $bcvar20, on step 3 we are sure that $bcvar is null and therefore issue an error. Reviewed By: mityal Differential Revision: D20558343 fbshipit-source-id: 520505039 --- .../nullsafe-default/TryWithResource.java | 26 +++++++++++++++++++ .../java/nullsafe-default/issues.exp | 2 ++ 2 files changed, 28 insertions(+) create mode 100644 infer/tests/codetoanalyze/java/nullsafe-default/TryWithResource.java diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/TryWithResource.java b/infer/tests/codetoanalyze/java/nullsafe-default/TryWithResource.java new file mode 100644 index 000000000..2a4a9ebfc --- /dev/null +++ b/infer/tests/codetoanalyze/java/nullsafe-default/TryWithResource.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +package codetoanalyze.java.nullsafe_default; + +import java.io.IOException; +import java.io.StringWriter; + +public class TryWithResource { + private static final int[] KEYS = {1}; + + private void FP_OK_StringWriterInTWRBlock() throws IOException { + // IMPORTANT: this for-loop is needed for issue to manifest. + for (int key : KEYS) { + // no-op + } + + try (StringWriter stringWriter = new StringWriter()) { + // no-op + } + } +} diff --git a/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp b/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp index 12b54e628..6e5dca395 100644 --- a/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp +++ b/infer/tests/codetoanalyze/java/nullsafe-default/issues.exp @@ -395,4 +395,6 @@ codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, codetoanalyze.java.nul codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, codetoanalyze.java.nullsafe_default.TrueFalseOnNull$TestStaticOneParam.notAnnotatedNegativeBranchIsBAD(java.lang.String):void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`s` is nullable and is not locally checked for null when calling `toString()`.] codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, codetoanalyze.java.nullsafe_default.TrueFalseOnNull$TestStaticOneParam.notAnnotatedPositiveBranchIsBAD(java.lang.String):void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`s` is nullable and is not locally checked for null when calling `toString()`.] codetoanalyze/java/nullsafe-default/TrueFalseOnNull.java, codetoanalyze.java.nullsafe_default.TrueFalseOnNull$TestStaticOneParam.trueOnNullPositiveBranchIsBAD(java.lang.String):void, 1, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [`s` is nullable and is not locally checked for null when calling `toString()`.] +codetoanalyze/java/nullsafe-default/TryWithResource.java, Linters_dummy_method, 1, ERADICATE_META_CLASS_NEEDS_FIXING, no_bucket, INFO, [] +codetoanalyze/java/nullsafe-default/TryWithResource.java, codetoanalyze.java.nullsafe_default.TryWithResource.FP_OK_StringWriterInTWRBlock():void, 6, ERADICATE_NULLABLE_DEREFERENCE, no_bucket, WARNING, [NullPointerException will be thrown at this line! Object is `null` and is dereferenced via calling `addSuppressed(...)`: null constant at line 22.] codetoanalyze/java/nullsafe-default/third-party-test-code/some/test/pckg/ThirdPartyTestClass.java, some.test.pckg.ThirdPartyTestClass.returnSpecifiedAsNullable():java.lang.String, 0, ERADICATE_RETURN_OVER_ANNOTATED, no_bucket, ADVICE, [Method `returnSpecifiedAsNullable()` is annotated with `@Nullable` but never returns null.]