From 4a2a326a252f7b16a96e4b3be8c4c6bfbbe28a7e Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Thu, 14 Mar 2024 17:14:27 +0100 Subject: [PATCH] [java-dfa] Visit catch(AIOOBE) block in case if array access can be successful GitOrigin-RevId: 49249d1a34b1b29b709bdb76e367ab3c705a05ef --- .../java/inst/ArrayAccessInstruction.java | 10 +++++++-- .../java/inst/ArrayStoreInstruction.java | 8 ++++++- .../jvm/problems/IndexOutOfBoundsProblem.java | 15 +++++++++---- .../ArrayIndexOutOfBounds.java | 22 +++++++++++++++++++ .../UnreachableCodeInspectionTest.java | 2 ++ 5 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/unreachableCode/ArrayIndexOutOfBounds.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayAccessInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayAccessInstruction.java index 6a291711490e..ddedc34bad50 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayAccessInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayAccessInstruction.java @@ -5,8 +5,8 @@ import com.intellij.codeInspection.dataFlow.TypeConstraint; import com.intellij.codeInspection.dataFlow.interpreter.DataFlowInterpreter; import com.intellij.codeInspection.dataFlow.java.JavaDfaHelpers; import com.intellij.codeInspection.dataFlow.jvm.descriptors.ArrayElementDescriptor; -import com.intellij.codeInspection.dataFlow.lang.DfaAnchor; import com.intellij.codeInspection.dataFlow.jvm.problems.IndexOutOfBoundsProblem; +import com.intellij.codeInspection.dataFlow.lang.DfaAnchor; import com.intellij.codeInspection.dataFlow.lang.ir.DfaInstructionState; import com.intellij.codeInspection.dataFlow.lang.ir.ExpressionPushingInstruction; import com.intellij.codeInspection.dataFlow.lang.ir.Instruction; @@ -19,6 +19,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; public class ArrayAccessInstruction extends ExpressionPushingInstruction { @@ -47,6 +48,10 @@ public class ArrayAccessInstruction extends ExpressionPushingInstruction { public DfaInstructionState[] accept(@NotNull DataFlowInterpreter interpreter, @NotNull DfaMemoryState stateBefore) { DfaValue index = stateBefore.pop(); DfaValue array = stateBefore.pop(); + List finalStates = new ArrayList<>(); + if (myOutOfBoundsTransfer != null) { + finalStates.addAll(IndexOutOfBoundsProblem.dispatchTransfer(interpreter, stateBefore, myOutOfBoundsTransfer)); + } DfaInstructionState[] states = myProblem.processOutOfBounds(interpreter, stateBefore, index, array, myOutOfBoundsTransfer); if (states != null) return states; LongRangeSet rangeSet = DfIntType.extractRange(stateBefore.getDfType(index)); @@ -68,7 +73,8 @@ public class ArrayAccessInstruction extends ExpressionPushingInstruction { } } pushResult(interpreter, stateBefore, result); - return nextStates(interpreter, stateBefore); + finalStates.add(nextState(interpreter, stateBefore)); + return finalStates.toArray(DfaInstructionState.EMPTY_ARRAY); } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayStoreInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayStoreInstruction.java index 2efac0aabf77..865beb5cbb3d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayStoreInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayStoreInstruction.java @@ -20,6 +20,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -53,6 +54,10 @@ public class ArrayStoreInstruction extends ExpressionPushingInstruction { DfaValue valueToStore = stateBefore.pop(); DfaValue index = stateBefore.pop(); DfaValue array = stateBefore.pop(); + List finalStates = new ArrayList<>(); + if (myOutOfBoundsTransfer != null) { + finalStates.addAll(IndexOutOfBoundsProblem.dispatchTransfer(interpreter, stateBefore, myOutOfBoundsTransfer)); + } DfaInstructionState[] states = myIndexProblem.processOutOfBounds(interpreter, stateBefore, index, array, myOutOfBoundsTransfer); if (states != null) return states; @@ -71,7 +76,8 @@ public class ArrayStoreInstruction extends ExpressionPushingInstruction { stateBefore.flushFieldsQualifiedBy(Set.of(array)); pushResult(interpreter, stateBefore, valueToStore); } - return nextStates(interpreter, stateBefore); + finalStates.add(nextState(interpreter, stateBefore)); + return finalStates.toArray(DfaInstructionState.EMPTY_ARRAY); } protected void checkArrayElementAssignability(@NotNull DataFlowInterpreter interpreter, diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/jvm/problems/IndexOutOfBoundsProblem.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/jvm/problems/IndexOutOfBoundsProblem.java index 4c3c84dfb3d2..ccbfac838ca2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/jvm/problems/IndexOutOfBoundsProblem.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/jvm/problems/IndexOutOfBoundsProblem.java @@ -45,14 +45,21 @@ public interface IndexOutOfBoundsProblem extends UnsatisfiedConditionProblem { interpreter.getListener().onCondition(this, index, failed, stateBefore); if (alwaysOutOfBounds) { if (outOfBoundsTransfer != null) { - List states = outOfBoundsTransfer.dispatch(stateBefore, interpreter); - for (DfaInstructionState state : states) { - state.getMemoryState().markEphemeral(); - } + List states = dispatchTransfer(interpreter, stateBefore, outOfBoundsTransfer); return states.toArray(DfaInstructionState.EMPTY_ARRAY); } return DfaInstructionState.EMPTY_ARRAY; } return null; } + + static @NotNull List dispatchTransfer(@NotNull DataFlowInterpreter interpreter, + @NotNull DfaMemoryState stateBefore, + @NotNull DfaControlTransferValue outOfBoundsTransfer) { + List states = outOfBoundsTransfer.dispatch(stateBefore, interpreter); + for (DfaInstructionState state : states) { + state.getMemoryState().markEphemeral(); + } + return states; + } } diff --git a/java/java-tests/testData/inspection/dataFlow/unreachableCode/ArrayIndexOutOfBounds.java b/java/java-tests/testData/inspection/dataFlow/unreachableCode/ArrayIndexOutOfBounds.java new file mode 100644 index 000000000000..0debcd619f9c --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/unreachableCode/ArrayIndexOutOfBounds.java @@ -0,0 +1,22 @@ + +class Test { + static final int[] DATA = {1, 2, 3}; + + int test(int value) { + try { + return DATA[value]; + } + catch (ArrayIndexOutOfBoundsException e) { + return -1; + } + } + + void test2(int value) { + try { + DATA[value] = -1; + } + catch (ArrayIndexOutOfBoundsException e) { + System.out.println(e); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/dataFlow/UnreachableCodeInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/dataFlow/UnreachableCodeInspectionTest.java index 1a2d67e96b78..52b4a3d1eaa9 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/dataFlow/UnreachableCodeInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/dataFlow/UnreachableCodeInspectionTest.java @@ -45,6 +45,8 @@ public class UnreachableCodeInspectionTest extends LightJavaCodeInsightFixtureTe public void testUnresolvedCast() { doTest(); } public void testUnresolvedCall() { doTest(); } + + public void testArrayIndexOutOfBounds() { doTest(); } private void doTest() { myFixture.configureByFile(getTestName(false) + ".java");