### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java,v retrieving revision 1.11 diff -u -r1.11 NullInfoRegistry.java --- compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java 19 Aug 2010 10:38:46 -0000 1.11 +++ compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java 18 Jan 2011 17:08:50 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 IBM Corporation and others. + * Copyright (c) 2006, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -402,5 +402,148 @@ return nullS + "]>"; //$NON-NLS-1$ } } + +/** + * Mark a local as potentially having been assigned to an unknown value. + * @param local the local to mark + */ +public void markPotentiallyUnknownBit(LocalVariableBinding local) { + // protected from non-object locals in calling methods + if (this != DEAD_END) { + this.tagBits |= NULL_FLAG_MASK; + int position; + long mask; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { + // use bits + mask = 1L << position; + isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$ + this.nullBit4 |= mask; + if (COVERAGE_TEST_FLAG) { + if(CoverageTestId == 46) { + this.nullBit4 = ~0; + } + } + } else { + // use extra vector + int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null) { + int length = vectorIndex + 1; + this.extra = new long[extraLength][]; + for (int j = 2; j < extraLength; j++) { + this.extra[j] = new long[length]; + } + } else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = this.extra[2].length)) { + for (int j = 2; j < extraLength; j++) { + System.arraycopy(this.extra[j], 0, + (this.extra[j] = new long[vectorIndex + 1]), 0, + oldLength); + } + } + } + mask = 1L << (position % BitCacheSize); + isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$ + this.extra[5][vectorIndex] |= mask; + if (COVERAGE_TEST_FLAG) { + if(CoverageTestId == 47) { + this.extra[5][vectorIndex] = ~0; + } + } + } + } +} + +public void markPotentiallyNullBit(LocalVariableBinding local) { + if (this != DEAD_END) { + this.tagBits |= NULL_FLAG_MASK; + int position; + long mask; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { + // use bits + mask = 1L << position; + isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$ + this.nullBit2 |= mask; + if (COVERAGE_TEST_FLAG) { + if(CoverageTestId == 40) { + this.nullBit4 = ~0; + } + } + } else { + // use extra vector + int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null) { + int length = vectorIndex + 1; + this.extra = new long[extraLength][]; + for (int j = 2; j < extraLength; j++) { + this.extra[j] = new long[length]; + } + } else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = this.extra[2].length)) { + for (int j = 2; j < extraLength; j++) { + System.arraycopy(this.extra[j], 0, + (this.extra[j] = new long[vectorIndex + 1]), 0, + oldLength); + } + } + } + mask = 1L << (position % BitCacheSize); + this.extra[3][vectorIndex] |= mask; + isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$ + if (COVERAGE_TEST_FLAG) { + if(CoverageTestId == 41) { + this.extra[5][vectorIndex] = ~0; + } + } + } + } +} + +public void markPotentiallyNonNullBit(LocalVariableBinding local) { + if (this != DEAD_END) { + this.tagBits |= NULL_FLAG_MASK; + int position; + long mask; + if ((position = local.id + this.maxFieldCount) < BitCacheSize) { + // use bits + mask = 1L << position; + isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$ + this.nullBit3 |= mask; + if (COVERAGE_TEST_FLAG) { + if(CoverageTestId == 42) { + this.nullBit4 = ~0; + } + } + } else { + // use extra vector + int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null) { + int length = vectorIndex + 1; + this.extra = new long[extraLength][]; + for (int j = 2; j < extraLength; j++) { + this.extra[j] = new long[length]; + } + } else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = this.extra[2].length)) { + for (int j = 2; j < extraLength; j++) { + System.arraycopy(this.extra[j], 0, + (this.extra[j] = new long[vectorIndex + 1]), 0, + oldLength); + } + } + } + mask = 1L << (position % BitCacheSize); + isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$ + this.extra[4][vectorIndex] |= mask; + if (COVERAGE_TEST_FLAG) { + if(CoverageTestId == 43) { + this.extra[5][vectorIndex] = ~0; + } + } + } + } +} } Index: compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java,v retrieving revision 1.71 diff -u -r1.71 UnconditionalFlowInfo.java --- compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java 16 Dec 2010 13:02:30 -0000 1.71 +++ compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java 18 Jan 2011 17:08:50 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -996,7 +996,7 @@ * @return true if the check passes (does not return * if the check fails) */ -private static boolean isTrue(boolean expression, String message) { +protected static boolean isTrue(boolean expression, String message) { if (!expression) throw new AssertionFailedException("assertion failed: " + message); //$NON-NLS-1$ return expression; @@ -1367,8 +1367,13 @@ this.nullBit4 &= mask; } else { // use extra vector - int vectorIndex ; - this.extra[2][vectorIndex = (position / BitCacheSize) - 1] + int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null || vectorIndex >= this.extra[2].length) { + // in case we attempt to reset the null info of a variable that has not been encountered + // before and for which no null bits exist. + return; + } + this.extra[2][vectorIndex] &= (mask = ~(1L << (position % BitCacheSize))); this.extra[3][vectorIndex] &= mask; this.extra[4][vectorIndex] &= mask; @@ -1400,6 +1405,23 @@ } else { // use extra vector int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null) { + int length = vectorIndex + 1; + this.extra = new long[extraLength][]; + for (int j = 0; j < extraLength; j++) { + this.extra[j] = new long[length]; + } + } + else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = this.extra[0].length)) { + for (int j = 0; j < extraLength; j++) { + System.arraycopy(this.extra[j], 0, + (this.extra[j] = new long[vectorIndex + 1]), 0, + oldLength); + } + } + } mask = 1L << (position % BitCacheSize); isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$ this.extra[5][vectorIndex] |= mask; @@ -1430,6 +1452,23 @@ } else { // use extra vector int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null) { + int length = vectorIndex + 1; + this.extra = new long[extraLength][]; + for (int j = 0; j < extraLength; j++) { + this.extra[j] = new long[length]; + } + } + else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = this.extra[0].length)) { + for (int j = 0; j < extraLength; j++) { + System.arraycopy(this.extra[j], 0, + (this.extra[j] = new long[vectorIndex + 1]), 0, + oldLength); + } + } + } mask = 1L << (position % BitCacheSize); this.extra[3][vectorIndex] |= mask; isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$ @@ -1460,6 +1499,23 @@ } else { // use extra vector int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null) { + int length = vectorIndex + 1; + this.extra = new long[extraLength][]; + for (int j = 0; j < extraLength; j++) { + this.extra[j] = new long[length]; + } + } + else { + int oldLength; // might need to grow the arrays + if (vectorIndex >= (oldLength = this.extra[0].length)) { + for (int j = 0; j < extraLength; j++) { + System.arraycopy(this.extra[j], 0, + (this.extra[j] = new long[vectorIndex + 1]), 0, + oldLength); + } + } + } mask = 1L << (position % BitCacheSize); isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$ this.extra[4][vectorIndex] |= mask; #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java,v retrieving revision 1.108 diff -u -r1.108 NullReferenceTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 18 Dec 2010 22:09:48 -0000 1.108 +++ src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java 18 Jan 2011 17:08:54 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 IBM Corporation and others. + * Copyright (c) 2005, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -13806,4 +13806,30 @@ "Done\n" + "-1"); } + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=333089 +// null analysis -- to make sure no AIOOBE or NPE is thrown while calling UnconditionalFlowInfo.markNullStatus(..) +public void testBug333089() { + this.runConformTest( + new String[] { + "X.java", + "public class X {\n" + + " public static void foo(Object s1) {\n" + + " int i00, i01, i02, i03, i04, i05, i06, i07, i08, i09;\n" + + " int i10, i11, i12, i13, i14, i15, i16, i17, i18, i19;\n" + + " int i20, i21, i22, i23, i24, i25, i26, i27, i28, i29;\n" + + " int i30, i31, i32, i33, i34, i35, i36, i37, i38, i39;\n" + + " int i40, i41, i42, i43, i44, i45, i46, i47, i48, i49;\n" + + " int i50, i51, i52, i53, i54, i55, i56, i57, i58, i59;\n" + + " int i60, i61, i62, i63, i64, i65, i66, i67, i68, i69;\n" + + " Object local1;\n" + + " if (s1 == null){}\n" + + " try {" + + " local1 = s1;\n" + + " } finally {\n" + + " }\n" + + " }\n" + + "}"}, + ""); +} } \ No newline at end of file