View | Details | Raw Unified | Return to bug 372319 | Differences between
and this patch

Collapse All | Expand All

(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConcurrentBatchCompilerTest.java (+205 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011, 2012 GK Software AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Stephan Herrmann - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.core.tests.compiler.regression;
12
13
import java.io.File;
14
import java.io.PrintWriter;
15
import java.util.Map;
16
17
import junit.framework.Test;
18
19
import org.eclipse.jdt.internal.compiler.ast.FakedTrackingVariable;
20
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
21
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
22
23
public class ConcurrentBatchCompilerTest extends BatchCompilerTest {
24
	
25
	public static Test suite() {
26
		return buildUniqueComplianceTestSuite(testClass(), ClassFileConstants.JDK1_6);
27
	}
28
	public static Class testClass() {
29
		return ConcurrentBatchCompilerTest.class;
30
	}
31
	public ConcurrentBatchCompilerTest(String name) {
32
		super(name);
33
	}
34
35
	Thread runner1;
36
	Thread runner2;
37
38
	static int COUNT = 100;
39
	
40
	/* Invoke the compiler COUNT times to increase bug probabililty. */
41
	protected boolean invokeCompiler(PrintWriter out, PrintWriter err, Object extraArguments, TestCompilationProgress compilationProgress) {
42
		boolean success = true;
43
		for (int j=0; j<COUNT; j++) {
44
			success &= super.invokeCompiler(out, err, extraArguments, compilationProgress);
45
		}
46
		return success;
47
	}
48
	
49
	/* Disambiguate file names for concurrent tests in the same directory. */
50
	protected String testName() {
51
		Thread current = Thread.currentThread();
52
		String baseName = super.testName();
53
		if (current == this.runner1)
54
			return baseName+"-Thread1";
55
		if (current == this.runner2)
56
			return baseName+"-Thread2";
57
		return baseName;
58
	}
59
	
60
	public void testBug372319() throws Throwable {
61
		try {
62
			FakedTrackingVariable.TEST_372319 = true;
63
	
64
			// expected error output for runner2 times COUNT:
65
			final StringBuffer errorOutput = new StringBuffer();
66
			for (int j=0; j<COUNT; j++)
67
				errorOutput.append("----------\n" +
68
						"1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/test01/X.java (at line 12)\n" +
69
						"	FileReader reader = getReader(\"somefile\");\n" +
70
						"	           ^^^^^^\n" +
71
						"Potential resource leak: \'reader\' may not be closed\n" +
72
						"----------\n" +
73
						"1 problem (1 error)");
74
	
75
			// collect exceptions indicating a failure:
76
			final Throwable[] thrown = new Throwable[2];
77
			
78
			this.runner1 = new Thread(new Runnable() {
79
					public void run() {
80
						try {
81
							runConformTest(new String[] {
82
								"org/eclipse/jdt/internal/launching/CompositeId.java",
83
								"/*******************************************************************************\n" + 
84
								" * Copyright (c) 2000, 2012 IBM Corporation and others.\n" + 
85
								" * All rights reserved. This program and the accompanying materials\n" + 
86
								" * are made available under the terms of the Eclipse Public License v1.0\n" + 
87
								" * which accompanies this distribution, and is available at\n" + 
88
								" * http://www.eclipse.org/legal/epl-v10.html\n" + 
89
								" * \n" + 
90
								" * Contributors:\n" + 
91
								" *     IBM Corporation - initial API and implementation\n" + 
92
								" *******************************************************************************/\n" + 
93
								"package org.eclipse.jdt.internal.launching;\n" + 
94
								"\n" + 
95
								"import java.util.ArrayList;\n" + 
96
								"\n" + 
97
								"/**\n" + 
98
								" * Utility class for id's made of multiple Strings\n" + 
99
								" */\n" + 
100
								"public class CompositeId {\n" + 
101
								"	private String[] fParts;\n" + 
102
								"	\n" + 
103
								"	public CompositeId(String[] parts) {\n" + 
104
								"		fParts= parts;\n" + 
105
								"	}\n" + 
106
								"	\n" + 
107
								"	public static CompositeId fromString(String idString) {\n" + 
108
								"		ArrayList<String> parts= new ArrayList<String>();\n" + 
109
								"		int commaIndex= idString.indexOf(',');\n" + 
110
								"		while (commaIndex > 0) {\n" + 
111
								"			int length= Integer.valueOf(idString.substring(0, commaIndex)).intValue();\n" + 
112
								"			String part= idString.substring(commaIndex+1, commaIndex+1+length);\n" + 
113
								"			parts.add(part);\n" + 
114
								"			idString= idString.substring(commaIndex+1+length);\n" + 
115
								"			commaIndex= idString.indexOf(',');\n" + 
116
								"		}\n" + 
117
								"		String[] result= parts.toArray(new String[parts.size()]);\n" + 
118
								"		return new CompositeId(result);\n" + 
119
								"	}\n" + 
120
								"	\n" + 
121
								"	@Override\n" + 
122
								"	public String toString() {\n" + 
123
								"		StringBuffer buf= new StringBuffer();\n" +
124
								"		for (int i= 0; i < fParts.length; i++) {\n" + 
125
								"			buf.append(fParts[i].length());\n" + 
126
								"			buf.append(',');\n" + 
127
								"			buf.append(fParts[i]);\n" + 
128
								"		}\n" + 
129
								"		return buf.toString();\n" + 
130
								"	}\n" + 
131
								"	\n" + 
132
								"	public String get(int index) {\n" + 
133
								"		return fParts[index];\n" + 
134
								"	}\n" + 
135
								"	\n" + 
136
								"	public int getPartCount() {\n" + 
137
								"		return fParts.length;\n" + 
138
								"	}\n" + 
139
								"}\n" + 
140
								""
141
							},
142
					        "\"" + OUTPUT_DIR +  File.separator + "org/eclipse/jdt/internal/launching/CompositeId.java\""
143
				            + " -1.5 -g -preserveAllLocals"
144
				            + " -proceedOnError -d \"" + OUTPUT_DIR + "\"",
145
							"",
146
							"",
147
							false);
148
						} catch (Throwable t) {
149
							thrown[0] = t;
150
						}
151
					}
152
			});
153
			this.runner2 = new Thread(new Runnable() {
154
				public void run() {
155
					try {
156
						// from ResourceLeakTests.test056e():
157
						Map options = getCompilerOptions();
158
						options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
159
						options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
160
						runNegativeTest(
161
							new String[] {
162
								"test01/X.java",
163
								"package test01;\n" +
164
								"import java.io.File;\n" +
165
								"import java.io.FileReader;\n" +
166
								"import java.io.IOException;\n" +
167
								"public class X {\n" +
168
								"    FileReader getReader(String filename) throws IOException {\n" +
169
								"        File file = new File(\"somefile\");\n" +
170
								"        FileReader fileReader = new FileReader(file);\n" +
171
								"        return fileReader;\n" + 		// don't complain here, pass responsibility to caller
172
								"    }\n" +
173
								"    void foo() throws IOException {\n" +
174
								"        FileReader reader = getReader(\"somefile\");\n" +
175
								"        char[] in = new char[50];\n" +
176
								"        reader.read(in);\n" +
177
								"    }\n" +
178
								"    public static void main(String[] args) throws IOException {\n" +
179
								"        new X().foo();\n" +
180
								"    }\n" +
181
								"}\n"
182
							},
183
					        "\"" + OUTPUT_DIR +  File.separator + "test01/X.java\""
184
				            + " -1.5 -g -preserveAllLocals -err:+resource"
185
				            + " -proceedOnError -d \"" + OUTPUT_DIR + "\"",
186
				            "",
187
							errorOutput.toString(),
188
							false);
189
					} catch (Throwable t) {
190
						thrown[1] = t;
191
					}
192
				}
193
			});
194
	
195
			this.runner2.start();
196
			this.runner1.start();
197
			this.runner1.join();
198
			this.runner2.join();
199
			if (thrown[0] != null) throw thrown[0];
200
			if (thrown[1] != null) throw thrown[1];
201
		} finally {
202
			FakedTrackingVariable.TEST_372319 = false;
203
		}
204
	}
205
}
(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java (+1 lines)
Lines 96-101 Link Here
96
	since_1_5.add(InternalHexFloatTest.class);
96
	since_1_5.add(InternalHexFloatTest.class);
97
	since_1_5.add(JavadocTest_1_5.class);
97
	since_1_5.add(JavadocTest_1_5.class);
98
	since_1_5.add(BatchCompilerTest.class);
98
	since_1_5.add(BatchCompilerTest.class);
99
	since_1_5.add(ConcurrentBatchCompilerTest.class);
99
	since_1_5.add(ExternalizeStringLiterals15Test.class);
100
	since_1_5.add(ExternalizeStringLiterals15Test.class);
100
	since_1_5.add(Deprecated15Test.class);
101
	since_1_5.add(Deprecated15Test.class);
101
	since_1_5.add(InnerEmulationTest_1_5.class);
102
	since_1_5.add(InnerEmulationTest_1_5.class);
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java (-1 / +1 lines)
Lines 84-90 Link Here
84
	}
84
	}
85
85
86
	// after having analysed exceptions above start tracking newly allocated resource:
86
	// after having analysed exceptions above start tracking newly allocated resource:
87
	if (FakedTrackingVariable.isAnyCloseable(this.resolvedType) && currentScope.compilerOptions().analyseResourceLeaks)
87
	if (currentScope.compilerOptions().analyseResourceLeaks && FakedTrackingVariable.isAnyCloseable(this.resolvedType))
88
		FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, this);
88
		FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, this);
89
89
90
	if (this.binding.declaringClass.isMemberType() && !this.binding.declaringClass.isStatic()) {
90
	if (this.binding.declaringClass.isMemberType() && !this.binding.declaringClass.isStatic()) {
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java (+10 lines)
Lines 60-65 Link Here
60
	private static final int REPORTED_POTENTIAL_LEAK = 32;
60
	private static final int REPORTED_POTENTIAL_LEAK = 32;
61
	// a location independent definitive problem has been reported against this resource:
61
	// a location independent definitive problem has been reported against this resource:
62
	private static final int REPORTED_DEFINITIVE_LEAK = 64;
62
	private static final int REPORTED_DEFINITIVE_LEAK = 64;
63
	
64
	public static boolean TEST_372319 = false; // see https://bugs.eclipse.org/372319
63
65
64
	/**
66
	/**
65
	 * Bitset of {@link #CLOSE_SEEN}, {@link #SHARED_WITH_OUTSIDE}, {@link #OWNED_BY_OUTSIDE}, {@link #CLOSED_IN_NESTED_METHOD}, {@link #REPORTED_EXPLICIT_CLOSE}, {@link #REPORTED_POTENTIAL_LEAK} and {@link #REPORTED_DEFINITIVE_LEAK}.
67
	 * Bitset of {@link #CLOSE_SEEN}, {@link #SHARED_WITH_OUTSIDE}, {@link #OWNED_BY_OUTSIDE}, {@link #CLOSED_IN_NESTED_METHOD}, {@link #REPORTED_EXPLICIT_CLOSE}, {@link #REPORTED_POTENTIAL_LEAK} and {@link #REPORTED_DEFINITIVE_LEAK}.
Lines 528-533 Link Here
528
	 * @return one of the constants FlowInfo.{NULL,POTENTIALLY_NULL,POTENTIALLY_NON_NULL,NON_NULL}.
530
	 * @return one of the constants FlowInfo.{NULL,POTENTIALLY_NULL,POTENTIALLY_NON_NULL,NON_NULL}.
529
	 */
531
	 */
530
	private int getNullStatusAggressively(LocalVariableBinding local, FlowInfo flowInfo) {
532
	private int getNullStatusAggressively(LocalVariableBinding local, FlowInfo flowInfo) {
533
		if (flowInfo == FlowInfo.DEAD_END) {
534
			return FlowInfo.UNKNOWN;
535
		}
531
		int reachMode = flowInfo.reachMode();
536
		int reachMode = flowInfo.reachMode();
532
		int status = 0;
537
		int status = 0;
533
		try {
538
		try {
Lines 535-540 Link Here
535
			if (reachMode != FlowInfo.REACHABLE)
540
			if (reachMode != FlowInfo.REACHABLE)
536
				flowInfo.tagBits &= ~FlowInfo.UNREACHABLE;
541
				flowInfo.tagBits &= ~FlowInfo.UNREACHABLE;
537
			status = flowInfo.nullStatus(local);
542
			status = flowInfo.nullStatus(local);
543
			if (TEST_372319) { // see https://bugs.eclipse.org/372319
544
				try {
545
					Thread.sleep(5); // increase probability of concurrency bug
546
				} catch (InterruptedException e) { /* nop */ }
547
			}
538
		} finally {
548
		} finally {
539
			// reset
549
			// reset
540
			flowInfo.tagBits |= reachMode;
550
			flowInfo.tagBits |= reachMode;
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java (-2 / +2 lines)
Lines 80-87 Link Here
80
	FlowInfo preInitInfo = null;
80
	FlowInfo preInitInfo = null;
81
	boolean shouldAnalyseResource = this.binding != null 
81
	boolean shouldAnalyseResource = this.binding != null 
82
			&& flowInfo.reachMode() == FlowInfo.REACHABLE
82
			&& flowInfo.reachMode() == FlowInfo.REACHABLE
83
			&& FakedTrackingVariable.isAnyCloseable(this.initialization.resolvedType)
83
			&& currentScope.compilerOptions().analyseResourceLeaks
84
			&& currentScope.compilerOptions().analyseResourceLeaks;
84
			&& FakedTrackingVariable.isAnyCloseable(this.initialization.resolvedType);
85
	if (shouldAnalyseResource) {
85
	if (shouldAnalyseResource) {
86
		preInitInfo = flowInfo.unconditionalCopy();
86
		preInitInfo = flowInfo.unconditionalCopy();
87
		// analysis of resource leaks needs additional context while analyzing the RHS:
87
		// analysis of resource leaks needs additional context while analyzing the RHS:
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java (-1 / +1 lines)
Lines 116-122 Link Here
116
		}
116
		}
117
117
118
		// after having analysed exceptions above start tracking newly allocated resource:
118
		// after having analysed exceptions above start tracking newly allocated resource:
119
		if (FakedTrackingVariable.isAnyCloseable(this.resolvedType) && currentScope.compilerOptions().analyseResourceLeaks) {
119
		if (currentScope.compilerOptions().analyseResourceLeaks && FakedTrackingVariable.isAnyCloseable(this.resolvedType)) {
120
			FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, this);
120
			FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, this);
121
		}
121
		}
122
122

Return to bug 372319