Bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK
Summary: [compiler][resource] Avoid remaining false positives found when compiling the...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.8   Edit
Hardware: Other Linux
: P3 normal (vote)
Target Milestone: 3.8 M6   Edit
Assignee: Stephan Herrmann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 370702 (view as bug list)
Depends on:
Blocks: 365710
  Show dependency tree
 
Reported: 2012-01-13 09:12 EST by Stephan Herrmann CLA
Modified: 2012-03-12 04:40 EDT (History)
5 users (show)

See Also:


Attachments
resource leak problems (3.80 KB, text/plain)
2012-01-13 09:12 EST, Stephan Herrmann CLA
no flags Details
resource leak warnings (9.33 KB, text/plain)
2012-01-16 09:14 EST, Deepak Azad CLA
no flags Details
Tests & fix (68.22 KB, patch)
2012-02-02 18:13 EST, Stephan Herrmann CLA
no flags Details | Diff
Remaining leak problems (1.34 KB, text/plain)
2012-02-02 18:26 EST, Stephan Herrmann CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Stephan Herrmann CLA 2012-01-13 09:12:27 EST
Created attachment 209453 [details]
resource leak problems

When compiling the Eclipse SDK with the latest patch in bug 358903 
I still see 22 warnings about definite resource leaks.
Some of these are false positives which should be avoided.

Some examples of trouble caused by specific syntax:

In org.eclipse.equinox.internal.util.io.ExternalizableDictionary:
  ObjectInputStream in = loader == null ? new ObjectInputStream(is) : (ObjectInputStream) new XObjectInputStream(loader, is);

-> it seems we choke on the conditional expression?

In org.eclipse.equinox.internal.p2.artifact.repository.RawMirrorRequest:
  destination = handler.link(new ProcessingStep[] {new MD5Verifier(descriptor.getProperty(IArtifactDescriptor.DOWNLOAD_MD5))}, destination, monitor);

-> how to handle resources in an array initializer?


Some others are related to special data flows not being understood.

For the records I'm attaching the list of problems I currently see.
Comment 1 Stephan Herrmann CLA 2012-01-13 17:14:59 EST
Bug 358903 introduced a disabled test that should be investigated
in the context of this bug, too: ResourceLeakTests#_test061q
Comment 2 Deepak Azad CLA 2012-01-16 09:14:34 EST
Created attachment 209555 [details]
resource leak warnings

(In reply to comment #0)
> Created attachment 209453 [details]
> resource leak problems
> 
> When compiling the Eclipse SDK with the latest patch in bug 358903 
> I still see 22 warnings about definite resource leaks.
> Some of these are false positives which should be avoided.

I see 57 warnings, see attachment.

My setup is 
- Fresh workspace.
- Import all plugin projects with source whose name start with org.eclipse.
Comment 3 Markus Keller CLA 2012-01-16 09:27:30 EST
I see one more here:
- Resource leak: 'out' is not closed at this location	EclipseTestRunner.java	/org.eclipse.test/src/org/eclipse/test	line 692	Java Problem

It uses this pattern:

    void foo(File outfile) {
        OutputStream out= System.out;
        if (outfile != null) {
            try {
                out = new FileOutputStream(outfile);
            } catch (java.io.IOException e) {
                throw new RuntimeException(e);
            }
        }
        setOutput(out);
    }
    private void setOutput(OutputStream out) { }
Comment 4 Stephan Herrmann CLA 2012-01-16 10:38:51 EST
(In reply to comment #2)
> > When compiling the Eclipse SDK with the latest patch in bug 358903 
> > I still see 22 warnings about definite resource leaks.
> > Some of these are false positives which should be avoided.
> 
> I see 57 warnings, see attachment.
> 
> My setup is 
> - Fresh workspace.
> - Import all plugin projects with source whose name start with org.eclipse.

Some differences (using the released version of bug 358903 plus the pending patch for bug 368709):

I don't see the warnings in

org.eclipse.pde.internal.ui.launcher.OpenLogDialog
org.eclipse.team.internal.ccvs.core.CVSTeamProvider
org.eclipse.update.internal.jarprocessor.ZipProcessor
org.eclipse.ltk.internal.core.refactoring.history.RefactoringHistoryManager

etc.

All these locations look OK to me. Which version were you using?

In my test workspace I currently see 25 resource leak warnings in org.eclipse.* (not counting jgit).
Comment 5 Deepak Azad CLA 2012-01-16 11:46:19 EST
I am compiling 3.8 M4 source against the latest in JDT/Core master which includes the fix for bug 368709.
Comment 6 Deepak Azad CLA 2012-01-16 11:54:51 EST
(In reply to comment #4)
> org.eclipse.pde.internal.ui.launcher.OpenLogDialog

private void readFile(PrintWriter writer) throws FileNotFoundException, IOException {
	BufferedReader bReader = new BufferedReader(new FileReader(logFile)); // warning
	while (bReader.ready())
		writer.println(bReader.readLine());
}

The warning I see is : "Resource leak: 'bReader' is never closed". This warning looks correct to me. But I have no clue why you do not see it.
Comment 7 Stephan Herrmann CLA 2012-01-17 15:13:19 EST
(In reply to comment #6)
> (In reply to comment #4)
> > org.eclipse.pde.internal.ui.launcher.OpenLogDialog
> 
> private void readFile(PrintWriter writer) throws FileNotFoundException,
> IOException {
> BufferedReader bReader = new BufferedReader(new FileReader(logFile)); //
> warning
> while (bReader.ready())
> writer.println(bReader.readLine());
> }
> 
> The warning I see is : "Resource leak: 'bReader' is never closed". This warning
> looks correct to me. But I have no clue why you do not see it.

Here's a clue: install a 1.4 JRE and you'll see that pde.ui (and all projects configured for 1.4) don't participate in this game: for the compiler they have no notion of resources because they have no type Closeable (or even AutoCloseable).

Here's my current steps and statistics:
From my development Eclipse (SDK + Mylyn + EGit) install all org.eclipse.* plug-ins as projects with source folder
- close *mylyn* and *egit*
Should be roughly 224 projects now.

Then fix broken Eclipse SDK sources (is that the code being shipped????):
- Fix 3 type errors in org.eclipse.equinox.util (ternary expression with type variables)
- Change all org.eclipse.jetty.* to Java2SE-6 (they use @Override for implementors)
- Remove one bogus package export from org.eclipse.pde.api.tools

To make resource leaks stick out I set workspace preference to report them as errors.

Using build I20111209-1447 I see:
82 resource leaks

Using today's HEAD (runtime workbench) I see:
31 resource leaks

As a next step I will classify these 31 problems.
Comment 8 Deepak Azad CLA 2012-01-18 05:56:57 EST
(In reply to comment #7)
> Here's a clue: install a 1.4 JRE and you'll see that pde.ui (and all projects
> configured for 1.4) don't participate in this game: for the compiler they have
> no notion of resources because they have no type Closeable (or even
> AutoCloseable).

Ha! :-) 

Now I added the 1.4 JRE to the workspace, but 1.4 projects are still using the 1.5 JRE. I guess something went wrong in the workspace, I will try to fix the problem and report the numbers here.
Comment 9 Deepak Azad CLA 2012-01-24 03:45:47 EST
(In reply to comment #8)
> Now I added the 1.4 JRE to the workspace, but 1.4 projects are still using the
> 1.5 JRE. I guess something went wrong in the workspace, I will try to fix the
> problem and report the numbers here.

This is because of bug 369480 :(
Comment 10 Ayushman Jain CLA 2012-01-24 05:26:31 EST
We report a potential leak warning here, but I don't see how a potential leak can come at the throw statement
class MyException extends Exception{}
class X{
	void foo(String fileName) throws IOException, MyException {
		FileReader       fileRead   = new FileReader(fileName);
		BufferedReader   bufRead    = new BufferedReader(fileRead);
		LineNumberReader lineReader = new LineNumberReader(bufRead);
		try {
		while (lineReader.readLine() != null) {
			bufRead.close();
			callSome();  // only this can throw MyException
		}
		} catch (MyException e) {
			throw e;  // Pot. leak reported here
		}
		bufRead.close(); 
	}
	private void callSome() throws MyException
	{
		
	}
}
Comment 11 Ayushman Jain CLA 2012-01-24 05:30:48 EST
Another example with unchecked exceptions. The analysis seems to think that the resources is always closed and gives a "can be managed with twr" warning
	void countFileLines(String fileName) throws IOException {
		FileReader       fileRead   = new FileReader(fileName);
		BufferedReader   bufRead    = new BufferedReader(fileRead);
		LineNumberReader lineReader = new LineNumberReader(bufRead);
		while (lineReader.readLine() != null) {
			if (lineReader.markSupported()) throw new IOException();
			bufRead.close();
		}
		bufRead.close();
	}

The throw new IOException() exposes an exit path where resource is not closed.
Comment 12 Ayushman Jain CLA 2012-01-24 06:28:47 EST
 public void goo() throws IOException {
 //   	LineNumberReader o = new LineNumberReader(null);
    	LineNumberReader o = null;
    	try {
    		o = new LineNumberReader(null);
    		
    	} catch (NumberFormatException e) {
    		
    	}
    }

In this case we get a pot. resource leak, but o is never really closed. If you uncomment the first statement, we get a resource leak. Seems weird.
Comment 13 Deepak Azad CLA 2012-01-24 07:13:26 EST
The following warning looks wrong

Resource leak: 'stream' is not closed at this location	ProcessingStepHandler.java	/org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/provisional/p2/artifact/repository/processing	line 188

private ArtifactOutputStream getArtifactStream(OutputStream stream) {
	OutputStream current = stream;
	while (current instanceof ProcessingStep)
		current = ((ProcessingStep) current).getDestination(); //warning
	if (current instanceof ArtifactOutputStream)
		return (ArtifactOutputStream) current;
	return null;
}
Comment 14 Stephan Herrmann CLA 2012-01-24 07:30:32 EST
(In reply to comment #13)
> The following warning looks wrong
> 
> Resource leak: 'stream' is not closed at this location   
> ProcessingStepHandler.java   
> /org.eclipse.equinox.p2.artifact.repository/src/org/eclipse/equinox/internal/provisional/p2/artifact/repository/processing
>    line 188
> 
> private ArtifactOutputStream getArtifactStream(OutputStream stream) {
>     OutputStream current = stream;
>     while (current instanceof ProcessingStep)
>         current = ((ProcessingStep) current).getDestination(); //warning
>     if (current instanceof ArtifactOutputStream)
>         return (ArtifactOutputStream) current;
>     return null;
> }

Why wrong?
Before the assignment 'current' holds a resource. This binding will
be lost by the assignment so we don't know what will happen with stream.

The only fishy thing I can see is that it should better be a pot.leak
warning, because we didn't create the stream within this method.
Is that what you meant?
Comment 15 Deepak Azad CLA 2012-01-24 07:43:11 EST
(In reply to comment #14)
> Why wrong?
> Before the assignment 'current' holds a resource. This binding will
> be lost by the assignment so we don't know what will happen with stream.
On the given line 'current' is reassigned, but the warning complains about 'stream'.

> The only fishy thing I can see is that it should better be a pot.leak
> warning, because we didn't create the stream within this method.
> Is that what you meant?
As per bug 362332 comment 5 we should not be reporting anything for 'stream' here. Or should we?
Comment 16 Deepak Azad CLA 2012-01-24 09:30:12 EST
I can see the following code pattern a bunch of times in the SDK. This example is from JDT UI. I think the code is perfectly fine here, but yet we have a warning.
- If an exception is thrown on creation of a resource, does that resource has to be closed? I think not.
- If an exception is thrown by 'close()' itself, can you do anything about closing the resource?
These are the 2 code paths I see that probably result in the warning.

Resource leak: 'stream' is not closed at this location	ProfileStore.java	/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter	line 270

-------------------------------------------------------------------------------
public void writeProfilesToFile(Collection<Profile> profiles, File file, String encoding) throws CoreException {
	final OutputStream stream;
	try {
		stream= new FileOutputStream(file);
		try {
			writeProfilesToStream(profiles, stream, encoding, fProfileVersioner);
		} finally {
			try { stream.close(); } catch (IOException e) { /* ignore */ }
		}
	} catch (IOException e) {
		throw createException(e, FormatterMessages.CodingStyleConfigurationBlock_error_serializing_xml_message); //warning on this line
	}
}
-------------------------------------------------------------------------------
Comment 17 Stephan Herrmann CLA 2012-01-29 07:08:07 EST
I'll try to find some root causes in this field. If there's a lot of different issues involved I will split out individual bugs that will have to be deferred post Juno then.
Comment 18 Stephan Herrmann CLA 2012-02-02 06:34:40 EST
(In reply to comment #10)
> We report a potential leak warning here, but I don't see how a potential leak
> can come at the throw statement
> class MyException extends Exception{}
> class X{
> void foo(String fileName) throws IOException, MyException {
> FileReader       fileRead   = new FileReader(fileName);
> BufferedReader   bufRead    = new BufferedReader(fileRead);
> LineNumberReader lineReader = new LineNumberReader(bufRead);
> try {
> while (lineReader.readLine() != null) {
> bufRead.close();
> callSome();  // only this can throw MyException
> }
> } catch (MyException e) {
> throw e;  // Pot. leak reported here
> }
> bufRead.close();
> }
> private void callSome() throws MyException
> {
> 
> }
> }

I filed bug 370424 for the underlying problem in our analysis machinery. The example in that bug is the same as here with simple substitutions:
 - resource allocation: assign null
 - resource close: assign nonnull
 - force diagnostic by 'throw' : force diagnostic by dereference
Comment 19 Stephan Herrmann CLA 2012-02-02 18:13:41 EST
Created attachment 210478 [details]
Tests & fix

This patch fixes all plain false positives I could find in the entire Eclipse SDK, including the examples from comment 3, comment 11, comment 13 and comment 16 and some more.

Most items were straight-forward application of existing concepts into hidden corners of the implementation, including:
- check the effect of a resource allocation only *after* analysing possible
  exceptions raised by the allocation
- consider all resources that are wrapped in an array as passed-to-outside
  since from there on we lose track of their state.
- propagate flags OWNED_BY_OUTSIDE and SHARED_WITH_OUTSIDE along a few more
  paths
- better detection of field references (checking (bits & Binding.FIELD) is
  *not* sufficient for QualifiedNameReference!)
- don't complain against variables on branches where they are definitely
  unassigned
- respect if a resource was closed in the finally block of any enclosing
  try statement
- better detect potential problems, in some cases they are signaled by
  pot.nonnull instead of the expected pot.null.


The only new concept is that we now include resource analysis into deferred checking for loops, which required a little refactoring in LoopingFlowContext.
I am yet to find an example where this would require corresponding changes in FinallyFlowContext.

Example from comment 10 is postponed due to bug 370424. Example from comment 12 suffers from the way info from try and from catch are merged, after the try-catch we no longer have definite info - I currently don't see an easy solution.
Comment 20 Stephan Herrmann CLA 2012-02-02 18:26:06 EST
Created attachment 210479 [details]
Remaining leak problems

With the patch from comment 19 compiling the entire Eclipse SDK is now down at reporting EIGHT definite resource leaks.

I'm attaching the list that I see (sources are a snapshot from a few weeks ago).

According to bug 358903 comment 13 the plan was to reduce almost 100 warnings against the SDK by estimated 30%. I think reducing the warnings by more than 90% should suffice for that plan :)
Comment 21 Stephan Herrmann CLA 2012-02-04 12:55:35 EST
After triple checking I released commit b5977e771dcaa856815c805c4cdc6cf2a2c18650 for 3.8 M6.
Comment 22 Stephan Herrmann CLA 2012-02-06 19:31:18 EST
*** Bug 370702 has been marked as a duplicate of this bug. ***
Comment 23 Srikanth Sankaran CLA 2012-03-12 04:40:57 EDT
Verified for 3.8 M6 using Build id: I20120306-0800