Bug 358903 - Filter practically unimportant resource leak warnings
Summary: Filter practically unimportant resource leak warnings
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.7   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.8 M5   Edit
Assignee: Stephan Herrmann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 360908 361073
  Show dependency tree
 
Reported: 2011-09-26 10:27 EDT by Deepak Azad CLA
Modified: 2012-01-24 09:52 EST (History)
7 users (show)

See Also:
satyam.kandula: review+


Attachments
Tests & fix v0.1 (23.90 KB, patch)
2012-01-01 16:06 EST, Stephan Herrmann CLA
no flags Details | Diff
Tests & fix v0.5 (46.77 KB, patch)
2012-01-05 10:49 EST, Stephan Herrmann CLA
no flags Details | Diff
Tests & fix v0.6 (58.70 KB, patch)
2012-01-05 17:02 EST, Stephan Herrmann CLA
no flags Details | Diff
Tests & fix v0.8 (84.84 KB, patch)
2012-01-07 19:26 EST, Stephan Herrmann CLA
no flags Details | Diff
Tests & Fix v0.9 (94.44 KB, patch)
2012-01-08 16:52 EST, Stephan Herrmann CLA
no flags Details | Diff
Tests & fix v0.9.5 (96.78 KB, patch)
2012-01-09 17:15 EST, Stephan Herrmann CLA
no flags Details | Diff
Tests & fix v0.9.6 (96.79 KB, patch)
2012-01-09 18:03 EST, Stephan Herrmann CLA
no flags Details | Diff
incremental changes (18.40 KB, patch)
2012-01-10 13:11 EST, Stephan Herrmann CLA
no flags Details | Diff
incremental changes 2 (117.77 KB, patch)
2012-01-12 08:40 EST, Stephan Herrmann CLA
no flags Details | Diff
ResourceLeakTests.java (100.75 KB, text/plain)
2012-01-12 08:43 EST, Stephan Herrmann CLA
no flags Details
incremental changes 3 (3.07 KB, patch)
2012-01-12 10:03 EST, Stephan Herrmann CLA
no flags Details | Diff
incremental change 4 (15.90 KB, patch)
2012-01-12 16:00 EST, Stephan Herrmann CLA
no flags Details | Diff
incremental changes 5 (16.17 KB, patch)
2012-01-13 10:40 EST, Stephan Herrmann CLA
no flags Details | Diff
incremental changes 6 (7.24 KB, patch)
2012-01-13 11:04 EST, Stephan Herrmann CLA
no flags Details | Diff
incremental change 7 (3.86 KB, patch)
2012-01-13 11:33 EST, Stephan Herrmann CLA
no flags Details | Diff
incremental changes 8 (18.33 KB, patch)
2012-01-13 14:09 EST, Stephan Herrmann CLA
no flags Details | Diff
Tests & fix v1.0 (272.39 KB, patch)
2012-01-13 16:17 EST, Stephan Herrmann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Deepak Azad CLA 2011-09-26 10:27:21 EDT
See also bug 349326.

The following 6 warnings in jdt.core are theoretically correct, but practically not important as no OS resource is leaked (the resources are StringReader, StringWriter etc). Is there a way we can filter these?

Resource leak: 'javaReader' is never closed	Scribe.java	/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter	line 2354

Resource leak: 'print' is not closed at this location	ClassFileReader.java	/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt	line 67

Resource leak: 'print' is not closed at this location	ClassFileReader.java	/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt	line 1181

Resource leak: 'reader' is never closed	Main.java	/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch	line 1794	

Resource leak: 'reader' is never closed	Scribe.java	/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter	line 2325	

Resource leak: 'writer' is never closed	ProblemReporter.java	/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem	line 1114

Thanks Markus for pointing these out!
Comment 1 Markus Keller CLA 2011-09-26 12:08:29 EDT
For Closeable classes from the JRE System Libraries, a good indication that close() is not really relevant is the absence of a finalize() method.

But that's not really a reliable predicate in general, and it's hard to track in practice when resources are wrapped in other resources like this:

    LineNumberReader resources = new LineNumberReader(new StringReader(string));
Comment 2 Deepak Azad CLA 2011-09-27 08:47:10 EDT
In practice if a large proportion of warnings are unimportant from a practical standpoint and we do not have a way to suppress them, we can also consider changing the default of 'Resource leak' warning to ignore.
Comment 3 Stephan Herrmann CLA 2011-09-27 09:37:24 EDT
(In reply to comment #2)
> In practice if a large proportion of warnings are unimportant from a practical
> standpoint and we do not have a way to suppress them, we can also consider
> changing the default of 'Resource leak' warning to ignore.

I think that should only be the very last resort because that would probably
mean that the vast majority of users will never learn about the warning.

I see two options to suppress warnings:

 @SuppressWarnings("resource")

 r.close();

:)

I'd say in Eclipse code I expect the large proportion of the warnings
to be already fixed sometime during the last 10 years. If a handful of
unimportant warnings remain this looks quite normal to me.

Regarding the classification important/unimportant: should we for
a start just use a white list of JDK classes that are known not to
use external resources (StringReader/Writer etc.)?
That would only leave us with the issue of instance nesting,
but it would be something I could start from.
Comment 4 Olivier Thomann CLA 2011-09-27 09:47:19 EDT
(In reply to comment #3)
> (In reply to comment #2)
> > In practice if a large proportion of warnings are unimportant from a practical
> > standpoint and we do not have a way to suppress them, we can also consider
> > changing the default of 'Resource leak' warning to ignore.
> 
> I think that should only be the very last resort because that would probably
> mean that the vast majority of users will never learn about the warning.
Same feeling for me. I find this warning useful. It can definitely help to find resources leaks.

>  @SuppressWarnings("resource")
yes, we should add this suppress warnings token.

Adding a while list might worth being investigated.
Comment 5 Stephan Herrmann CLA 2011-09-27 14:48:45 EDT
(In reply to comment #4)
> >  @SuppressWarnings("resource")
> yes, we should add this suppress warnings token.

It's already part of the patch in bug 349326 :)

Related question: would we also want to support a corresponding
token for the batch compiler? I started to think about his when I
noticed that TestVerifier/VerifyTests raises the new warning and one way
to avoid clutter in the test output might be to pass 
  -warn:-resource
when compiling VerifyTests.java?

Should I file a new bug for that?
Comment 6 Deepak Azad CLA 2011-09-30 02:00:06 EDT
(In reply to comment #3)
> Regarding the classification important/unimportant: should we for
> a start just use a white list of JDK classes that are known not to
> use external resources (StringReader/Writer etc.)?
> That would only leave us with the issue of instance nesting,
> but it would be something I could start from.

Let's take an example (org.eclipse.jdt.internal.compiler.batch.Main: line 1794)

LineNumberReader reader = new LineNumberReader(new StringReader(new String(Util.getFileCharContent(new File(arg.substring(1)), null))));

This example is fairly involved and even in this case wouldn't it be simpler to just check if any type used on the rhs has a finalize method or not? If no finalize method if found, it is probably safe to infer that there is no OS resource involved.

Preparing a list would be error prone, and I assume even there the basis of inclusion or exclusion of a type would be the presence or absence of finalize(). Hence, why not simply do on the fly checks?
Comment 7 Deepak Azad CLA 2011-09-30 02:10:49 EDT
Of course abstract classes like java.io.InputStream and java.io.OutputStream do not have finalize methods.
Comment 8 Markus Keller CLA 2011-09-30 09:08:30 EDT
(In reply to comment #6)
> Preparing a list would be error prone, and I assume even there the basis of
> inclusion or exclusion of a type would be the presence or absence of
> finalize(). Hence, why not simply do on the fly checks?

No, the list would have to be hand-checked and would only include the common cases from the JRE libraries that are safe because they only process a given string or array. I really meant comment 1 exactly as I wrote it.

The finalize() method is just a pattern used in the JRE, but I'm sure there are many third-party resource classes that don't have a finalize() method. AFAICS, even the java.nio.* classes don't have finalizers. Actually only java.io.FileInput/OutputStream and java.util.zip.ZipFile do use finalize().
Comment 9 Stephan Herrmann CLA 2011-10-01 08:32:29 EDT
I suggest to use 2 white lists, actually:

Group 1: classes that wrap another Closeable

Group 2: (leaf) classes that are known not to allocate any OS resources

Thus we can safely state that any expression
  new Group1_A(new Group1_B(value_from_group_2))
does not require tracking by our analysis.

A white list is not a complete solution but in this case I think
it's the best balance between avoiding false positives and effort
(development & runtime).
Comment 10 Markus Keller CLA 2011-10-03 10:23:49 EDT
(In reply to comment #9)
> I suggest to use 2 white lists, actually:

Sounds good.
Comment 11 Deepak Azad CLA 2011-10-16 07:49:06 EDT
I don't know how easy or difficult is the complete solution, but as a first step we should be able to eliminate warnings on the following pattern

     Group1_Type resource= new Group1_Type();

There are a few of these in jdt.ui which involve one of StringReader,StringWriter, ByteArrayOutputStream, ByteArrayInputStream.
Comment 12 Deepak Azad CLA 2011-10-16 07:50:48 EDT
(In reply to comment #11)
>      Group1_Type resource= new Group1_Type();
I meant Group2 :)
      Group2_Type resource= new Group2_Type();
Comment 13 Markus Keller CLA 2011-12-02 06:13:26 EST
Could we put this and the dependent bugs on the plan for M5?

The builder has been updated for N20111201-2000, so this will create almost 100 compiler warnings in the SDK -- and from a quick glance, I'd say about 30% are practically unimportant.
Comment 14 Stephan Herrmann CLA 2011-12-02 14:02:21 EST
(In reply to comment #13)
> Could we put this and the dependent bugs on the plan for M5?

I'll assess feasibility once the null annotations work is fully done for M4
 
> The builder has been updated for N20111201-2000, so this will create almost 100
> compiler warnings in the SDK -- and from a quick glance, I'd say about 30% are
> practically unimportant.

BTW: how can I see which builder is used (for which build)?
Comment 15 Ayushman Jain CLA 2011-12-05 08:52:49 EST
Please set the default for the unclosed resource back to "warning" since it has been changed to "ignore" via bug 365566.
Only changes in IrritantSet and BatchCompilerTest will need to be backed out. Rest everything is ok.
Comment 16 Stephan Herrmann CLA 2012-01-01 16:06:20 EST
Created attachment 208899 [details]
Tests & fix v0.1

Here's a first take at implementing the two white lists
and using these during analysis.

While the implementation still has a few FIXMEs, I'd appreciate
if someone could already have a look at these:
- tests: do you agree with the expected results?
- the concrete white lists (in TypeConstants)
Comment 17 Deepak Azad CLA 2012-01-02 03:22:49 EST
(In reply to comment #16)
> - the concrete white lists (in TypeConstants)
JAVA_IO_RESOURCE_FREE_CLOSEABLES - This list looks OK. 

However, JAVA_IO_WRAPPER_CLOSEABLES is missing quite a few types e.g. LineNumberReader, DataInputStream, DataInputStream, FilterReader, ObjectOutputStream, ObjectInputStream etc.

(I am wondering whether it is safe to say that if constructors for a 'resource type' in java.io package accept as parameter one of the type from JAVA_IO_RESOURCE_FREE_CLOSEABLES then all those 'resource types' belong in JAVA_IO_WRAPPER_CLOSEABLES. Maybe we can use this logic in code instead of enumerating all types in JAVA_IO_WRAPPER_CLOSEABLES?)

> - tests: do you agree with the expected results?
I have not tried the patch yet.
Comment 18 Stephan Herrmann CLA 2012-01-02 15:53:50 EST
(In reply to comment #17)
> [...]
> However, JAVA_IO_WRAPPER_CLOSEABLES is missing quite a few types e.g.
> LineNumberReader, DataInputStream, DataInputStream, FilterReader,
> ObjectOutputStream, ObjectInputStream etc.

Thanks, yep that's quite a list ...

> (I am wondering whether it is safe to say that if constructors for a 'resource
> type' in java.io package accept as parameter one of the type from
> JAVA_IO_RESOURCE_FREE_CLOSEABLES then all those 'resource types' belong in
> JAVA_IO_WRAPPER_CLOSEABLES. Maybe we can use this logic in code instead of
> enumerating all types in JAVA_IO_WRAPPER_CLOSEABLES?)

a) the parameter need not be a RESOURCE_FREE_CLOSEABLE, any Closeable
indicates a potential wrapper.

b) we cannot prove that this logic is safe. Hence I'd feel more 
comfortable with applying the logic offline, checking each match
manually and storing the result in a manifest white list.
 
> > - tests: do you agree with the expected results?
> I have not tried the patch yet.

I'd hoped in a TDD spirit we could agree on the expected test results
before the patch is finalized and tried :)
Comment 19 Stephan Herrmann CLA 2012-01-05 10:49:58 EST
Created attachment 209082 [details]
Tests & fix v0.5

Updates:

Handle more combinations like directly nested allocation vs. storing
chained closeables in a local variable, vs. assignment-as-argument etc.
(see the tests).

More complete handling if arbitrary points in the chain are (potentially)
closed. 

No longer treat BitWrapperCloseable and BitResourceFreeCloseable as
inheritable properties. See FileReader for an example:
It's a subclass of a wrapper (InputStreamReader), but hides this fact from
clients, i.e., FileReader is solely responsible for the underlying resource.

CAVEAT: things *could* get messy when a resource is obtained by calling a 
method returning InputStreamReader which could actually return a FileReader.
Analysis would think it's a wrapper, but it actually holds an OS resource.
However, since we are shy to report against resources obtained from another
method this should be tolerable I think.

I'm now down to one FIXME in the code.
I haven't yet added much to the white lists.

Note that the current patch also covers bug 360908 and bug 361073.
Comment 20 Stephan Herrmann CLA 2012-01-05 17:02:07 EST
Created attachment 209107 [details]
Tests & fix v0.6

Please don't use the previous patch it caused a regression when
trying to compile expressions of this shape
   resource = new Wrapper(resource);
From this I created a recursive link structure resulting in stack overflow 
due to infinite recursion.

This pattern is now recognized. Normally, the pattern would also raise
a warning that the previous value of resource would leak. I've updated
the implementation to remain silent in this case because the responsibility
for resource remains the same with just one more level of wrappers.

Also warnings are now correctly raised in this kind of code:
   resource1 = ...
   resource2 = new Wrapper(resource1 = resource3);
In order to detect that the old value of resource1 may leak,
we need to capture the null-info before the outer assignment
analyzes its rhs.

With this patch and with resource leak warning enabled I'm down to
4 warnings in JDT/Core:

Resource leak: 'file' is never closed	Util.java	/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util	line 977	Java Problem

--> will be handled in bug 362332


Resource leak: 'reader' is never closed	Scribe.java	/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter	line 2325	Java Problem

--> I see no obvious reason why this code should be OK :-/


Resource leak: 'javaReader' is never closed	Scribe.java	/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter	line 2354	Java Problem
Resource leak: 'jarFile' is never closed	CheckDebugAttributes.java	/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core	line 60	Java Problem

--> these readers are JDT/Core's own resource wrappers, similar to 
  those in java.io, but we wouldn't want to put our own classes on the
  white list :-/
Comment 21 Ayushman Jain CLA 2012-01-06 08:43:05 EST
(In reply to comment #20)
> Created attachment 209107 [details]
> Tests & fix v0.6

This patch causes an NPE in UnconditionalFlowInfo because it calls markAs..() methods with a possibly null argument. See bug 368027 comment 0
Comment 22 Stephan Herrmann CLA 2012-01-06 10:12:20 EST
(In reply to comment #21)
> (In reply to comment #20)
> > Created attachment 209107 [details]
> > Tests & fix v0.6
> 
> This patch causes an NPE in UnconditionalFlowInfo because it calls markAs..()
> methods with a possibly null argument. See bug 368027 comment 0

Wow, that's bad. As I'm not in my JDT/Core-dev-environment currently,
I can only give a theoretical answer from the sources:

I checked before that a regular FakedTrackingVariable has a non-null
binding (unless the ctor bails out with an exception).
However, the lately added marker instance SELF_WRAP doesn't follow
this rule.

Most likely, this signals that there are more exuction paths that need
to respect the "res = new Wrapper(res);" pattern.

I'll investigate later today.

@Deepak: any chance you could associate the NPE to which plugin you
were compiling? If not: is there in easy way to setup a workspace
with full SDK sources for testing? (e.g., a .psf?)
Comment 23 Deepak Azad CLA 2012-01-06 10:23:56 EST
(In reply to comment #22)
> @Deepak: any chance you could associate the NPE to which plugin you
> were compiling? If not: is there in easy way to setup a workspace
> with full SDK sources for testing? (e.g., a .psf?)

The NPE happened with several plugins e.g. o.e.jdt.launching. It also happens with reconcile operations. So I am not sure what exactly causes it, but I am able to reproduce it in my workspace.

I was trying to look at the number of warnings in the SDK (see comment 13). My setup is
- Start Eclipse (I started with M4) in a fresh workspace
- File > Import > Plug-ins and Fragments
- Select 'Projects with Source folders'
- 'Add All'
- Finish
Compilation takes a while but the steps are simple enough.
Comment 24 Deepak Azad CLA 2012-01-06 11:39:15 EST
(In reply to comment #20)
> --> these readers are JDT/Core's own resource wrappers, similar to 
>   those in java.io, but we wouldn't want to put our own classes on the
>   white list :-/

In Platform Text there is at least one instance where a StringReader is wrapped in org.eclipse.jface.internal.text.html.HTML2TextReader, which is a candidate for JAVA_IO_WRAPPER_CLOSEABLES. I also came across org.eclipse.jetty.util.ByteArrayISO8859Writer, which is a candidate for JAVA_IO_RESOURCE_FREE_CLOSEABLES.

So my question is are we sure that we want to hardcode the white lists? It might be better to create preferences with appropriate defaults. No?
Comment 25 Ayushman Jain CLA 2012-01-06 11:44:41 EST
(In reply to comment #24)
> So my question is are we sure that we want to hardcode the white lists? It
> might be better to create preferences with appropriate defaults. No?

I prefer this. Coincidentally, I'm fighting for the same in bug 365437. :)
Comment 26 Stephan Herrmann CLA 2012-01-06 16:38:35 EST
(In reply to comment #23)
> I was trying to look at the number of warnings in the SDK (see comment 13). My
> setup is
> - Start Eclipse (I started with M4) in a fresh workspace
> - File > Import > Plug-ins and Fragments
> - Select 'Projects with Source folders'
> - 'Add All'
> - Finish
> Compilation takes a while but the steps are simple enough.

Thanks, that looks simple indeed, and works pretty well (after I mounted
another disk for the required 1GB :)

However, I can't quite believe the result of the operation:
About a dozen projects has compile errors of all sorts!! Some of them
*could* be due to the fact that I don't have a Foundation-1.1 JRE.
(Any ideas where I could get one for linux??)
After removing those projects next I saw over 13000 warnings!!
Is the SDK code really that bad??
Only after disabling for the entire workspace problems regarding
generics and restricted/discouraged access, I'm now down to 150 warnings
so I can start investigating the remaining resource warnings....
Comment 27 Dani Megert CLA 2012-01-07 03:54:52 EST
(In reply to comment #25)
> (In reply to comment #24)
> > So my question is are we sure that we want to hardcode the white lists? It
> > might be better to create preferences with appropriate defaults. No?
> 
> I prefer this. Coincidentally, I'm fighting for the same in bug 365437. :)

We shouldn't pollute the preference UI for 1% corner cases. If we really need this configurable then we might consider adding it in JDT Core with reasonable defaults but don't surface it in the UI. That way power users can still change it in the prefs file directly.
Comment 28 Stephan Herrmann CLA 2012-01-07 05:03:24 EST
(In reply to comment #27)
> (In reply to comment #25)
> > (In reply to comment #24)
> > > So my question is are we sure that we want to hardcode the white lists? It
> > > might be better to create preferences with appropriate defaults. No?
> > 
> > I prefer this. Coincidentally, I'm fighting for the same in bug 365437. :)
> 
> We shouldn't pollute the preference UI for 1% corner cases. If we really need
> this configurable then we might consider adding it in JDT Core with reasonable
> defaults but don't surface it in the UI. That way power users can still change
> it in the prefs file directly.

I agree that normal users shouldn't see such an option in the UI.
It's indeed a corner case and it would take quite a bit of talking
to explain when exactly a Closeable type should be classified as a
wrapper or as resource-free.

Conceptually, I would even argue that this shouldn't be a configuration
option for the compiler but an annotation by which library developers
mark their classes, so everybody using the library can automatically
benefit from that classification.

To keep this bug focused I suggest to leave it as hard coded lists
for now and wait how desperately users would want to fine tune this.
Comment 29 Stephan Herrmann CLA 2012-01-07 12:46:27 EST
Oops: my comments don't match to the reported problems for these:

(In reply to comment #20)
> With this patch and with resource leak warning enabled I'm down to
> 4 warnings in JDT/Core:
> 
> Resource leak: 'reader' is never closed    Scribe.java   
> /org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter    line 2325
>    Java Problem
> Resource leak: 'javaReader' is never closed    Scribe.java   
> /org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter    line 2354
>    Java Problem
> Resource leak: 'jarFile' is never closed    CheckDebugAttributes.java   
> /org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core    line 60    Java
> Problem

The two occurrences in Scribe are OK (custom resource wrappers).

But the occurrences in CheckDebugAttributes looks like a real bug to me!
We read a ZipFile (using entries()) and that's all we do with it!

However, I noticed the issue only while accidentally compiling against
a 1.7 JRE where ZipFile implements Closeable, which is not the case in
older JRE's.
Comment 30 Stephan Herrmann CLA 2012-01-07 19:26:38 EST
Created attachment 209169 [details]
Tests & fix v0.8

Wow, precise analysis of various structures of nested resource instances
across various syntactic options turns out to be pretty complex.

The good news is: the new patch also covers bug 360908, bug 361073,
bug 362331 and bug 362332.

Specifically bug 362331 required a change in implementation strategy
(to be documented there) which had some impact also on this bug.
So it's good to address both issues in one patch rather than going back
and forth.

Ah, and yes, the strategy change also resolved the NPE from bug 368027
(the special instance SELF_WRAP, which indeed was the culprit, is no
longer needed).

When compiling the full SDK (almost full, see comment 26) with this patch
I'm down at 31 resource warnings (after restoring the intended default).
Out of these 2 or 3 could still be avoided by smarter analysis.
Several warnings demonstrate an inherent limitation: the analysis cannot
cope well with variables assigned from various sources on different
branches, since we have no representation for values, only variables and
their status (wrt def / null / closed).

I've added java.* classes to the white lists as they occurred in the 
sources, but lists are still not complete.
Comment 31 Stephan Herrmann CLA 2012-01-08 16:52:38 EST
Created attachment 209179 [details]
Tests & Fix v0.9

Mostly cleanup, including copyright.

Values read from a field are now excluded from analysis.
Comment 32 Stephan Herrmann CLA 2012-01-08 17:54:59 EST
More candidate types for inclusion in the wrapper white list
(in addition to the ones contained in the patch):

java.io:
 DataInputStream, PushbackInputStream, SequenceInputStream,
 StringBufferInputStream, DataOutputStream, PrintStream, PushbackReader.
 OutputStreamWriter

NOT: PipedInputStream, PipedOutputStream, PipedReader, PipedWriter

java.util.zip:
 GZIPInputStream, InflaterInputStream, DeflaterInputStream,
 CheckedInputStream, ZipInputStream, JarInputStream,
 GZIPOutputStream, InflaterOutputStream, DeflaterOutputStream, 
 CheckedOutputStream, ZipOutputStream, JarOutputStream

java.security:
 DigestInputStream, DigestOutputStream

java.beans:
 XMLEncoder, XMLDecoder

javax.sound.sampled:
 AudioInputStream
Comment 33 Srikanth Sankaran CLA 2012-01-08 23:44:14 EST
Satyam, could you please review the latest patch from comment#31
bearing in mind comment# 32 ? TIA.
Comment 34 Deepak Azad CLA 2012-01-09 01:22:14 EST
(In reply to comment #26)
> However, I can't quite believe the result of the operation:
> About a dozen projects has compile errors of all sorts!! Some of them
> *could* be due to the fact that I don't have a Foundation-1.1 JRE.
> (Any ideas where I could get one for linux??)
Yup, I ignored these projects.

> After removing those projects next I saw over 13000 warnings!!
> Is the SDK code really that bad??
> Only after disabling for the entire workspace problems regarding
> generics and restricted/discouraged access, I'm now down to 150 warnings
> so I can start investigating the remaining resource warnings....
In the problems view I use 'Group by > Java Problem Type' and then focus on 'Potential Programming Problems' group.

(In reply to comment #27)
> We shouldn't pollute the preference UI for 1% corner cases. If we really need
> this configurable then we might consider adding it in JDT Core with reasonable
> defaults but don't surface it in the UI. That way power users can still change
> it in the prefs file directly.
I am OK with not exposing the options in the UI. One example of a power user would be our Eclipse SDK build.

(In reply to comment #28)
> To keep this bug focused I suggest to leave it as hard coded lists
> for now and wait how desperately users would want to fine tune this.
Sure, we can look at the number of warnings left in the SDK after this bug is fixed and then take a call.
Comment 35 Deepak Azad CLA 2012-01-09 03:47:55 EST
(In reply to comment #30)
> When compiling the full SDK (almost full, see comment 26) with this patch
> I'm down at 31 resource warnings (after restoring the intended default).
> Out of these 2 or 3 could still be avoided by smarter analysis.
> Several warnings demonstrate an inherent limitation: the analysis cannot
> cope well with variables assigned from various sources on different
> branches, since we have no representation for values, only variables and
> their status (wrt def / null / closed).

With patch v0.9 I see 61 warnings, but that is probably because I have not deleted any projects and my workspace includes org.apache plugins as well. In any case the patch works well, and most of the warnings look valid to me.

I also no longer see the NPE from comment 21.
Comment 36 Stephan Herrmann CLA 2012-01-09 16:46:37 EST
Some explanations as background for the review:

At the input of the resource analysis we use the bitset
ReferenceBinding.typeBits which was introduced in bug 349326 with the 2
bits BitAutoCloseable and BitCloseable (from TypeIds). To these, this bug
adds BitWrapperCloseable and BitResourceFreeCloseable to mark members of
our two new white lists. Note that the former 2 bits are inheritable,
whereas the latter two are not (see comment 19).

The main part of the analysis uses the concept of a FakedTrackingVariable,
also introduced in bug 349326: when an AutoCloseable value is assigned
to a local variable we add this tracking variable for which we record
nullness information with these interpretations: NULL: not-closed,
NON_NULL: closed; plus the corresponding POTENTIALLY_... values.

Originally, tracking variables were associated only to local variables.
With this patch we also have the option to temporarily store a tracking
variable for an AllocationExpression in order to detect patterns like:
 new Wrapper(new InnerResources()); // not relevant if inner is resource-free
and
 new Resource().read();  // not closed
 new Resource().close(); // OK

For any chained resources (new Wrapper(new Inner())) we now link the
tracking variables using FTV.innerTracker so that we can detect whether
an underlying resource (the innermost) is closed directly or indirectly 
via its wrapper chain.

An especially tricky situation is this:
 res = new Wrapper(res);
As before we need to analyze the kind of wrapper chain against our 
white lists, but also we must distinguish this from
 res1 = new Wrapper(res2);
In the latter case the assignment forgets the resource previously stored in
res1, and if that was not closed we have a leak. By contrast the former 
assignment creates a matryoshka where no resource is forgotten.
This is a challenge for the implementation because during AST traversal
we have no single location that sees both applications of 'res'.

To solve this, method FTV.preConnectTrackerAcrossAssignment(..) pushes the
LHS of the assignment into any AllocationExpression on the RHS, to be
picked up when analyzing the allocation.

Another complication is caused by statements like
  res = new Wrapper( res2 = new Inner())
This means we have to unwrap any assignments (and similarly: casts) in the
position of an argument to a resource-type allocation expression.

Associating a tracking variable to an allocation expression requires 
additional care, because now we can have tracking variables with no local
variable binding associated (in field originalBinding), which previously
would never occur.

Finally I'm introducing a distinction of expression kinds from which we
obtain a resource:
 - when obtaining a resource from a message send, we are uncertain which
   side is responsible for closing -> mark as potentially closed.
   similarly for an array reference.
 - when obtaining a resource from a field read, assume that the resource
   has a longer life cycle than the current method execution ->
   pretend it is properly closed.

Most of this logic is implemented in class FakedTrackingVariable. A few
changes result from moving methods from BlockScope into FTV.

The interesting new points of interaction are in 
 - Assignment: trigger analysis: check against white list and for wrappers
   drill into the first argument
 - LocalDeclaration & Assignment: trigger the left-to-right push mentioned
   above - then do normal analysis of RHS - then collect information
   right-to-left.


For more detailed description please see the comments in the code - 
or ask me :)
Comment 37 Stephan Herrmann CLA 2012-01-09 17:15:03 EST
Created attachment 209232 [details]
Tests & fix v0.9.5

Same patch with extended white lists from comment 32
(StringBufferInputStream was wrongly listed as a wrapper, is actually
resource-free).

When compiling the SDK with this patch I only see 25 resource warnings.
Comment 38 Stephan Herrmann CLA 2012-01-09 18:03:57 EST
Created attachment 209234 [details]
Tests & fix v0.9.6

Previous patch introduced a copy&paste error, 
detected by NegativeCodeSnippetTest.
Comment 39 Satyam Kandula CLA 2012-01-10 01:33:00 EST
(In reply to comment #36)
Thanks for the detailed explanation. I have started the review and will give you any comments I have periodically. To start with, what should happen for the subtypes of thewhite list types?
For eg:
#####
import java.io.StringReader;
import java.io.IOException;
public class X {
    void foo() throws IOException {
        StringReader string  = new SReader("content");
        System.out.println(string.read());
    }
    public static void main(String[] args) throws IOException {
        new X().foo();
    }
}
class SReader extends StringReader {
    public SReader(String arg0) {
        super(arg0);        
    }    
}
#####
SReader extends StringReader in the white list without overriding close. I
believe resource leaks should not be reported even for this.
Comment 40 Stephan Herrmann CLA 2012-01-10 06:06:25 EST
(In reply to comment #39)
> (In reply to comment #36)
> Thanks for the detailed explanation. I have started the review and will give
> you any comments I have periodically. To start with, what should happen for the
> subtypes of thewhite list types?
> For eg:
> #####
> import java.io.StringReader;
> import java.io.IOException;
> public class X {
>     void foo() throws IOException {
>         StringReader string  = new SReader("content");
>         System.out.println(string.read());
>     }
>     public static void main(String[] args) throws IOException {
>         new X().foo();
>     }
> }
> class SReader extends StringReader {
>     public SReader(String arg0) {
>         super(arg0);        
>     }    
> }
> #####
> SReader extends StringReader in the white list without overriding close. I
> believe resource leaks should not be reported even for this.

My implementation assumes nothing about such subtypes. This encodes the
policy that we know for sure only for the exact types we've checked for 
inclusion in the white list.

Your heuristic to inherit from a resource-free Closeable and not override
close is a good one, but I decided to not implement *any* heuristic of
this kind.

I'm not sure how relevant your case is. If relevant we could already file
a further RFE. Otherwise we might wait if it is more than an extreme
corner case in practice?
Comment 41 Satyam Kandula CLA 2012-01-10 06:22:52 EST
(In reply to comment #40)
We could track the problem in a separate bug, but as there is no user defined white list, these types of filters could help reducing some more false positives.
Comment 42 Satyam Kandula CLA 2012-01-10 06:27:41 EST
(In reply to comment #41)
> I'm not sure how relevant your case is. If relevant we could already file
> a further RFE. Otherwise we might wait if it is more than an extreme
> corner case in practice?
I could see subtypes of ByteArrayInputStream in my workspace.
Comment 43 Deepak Azad CLA 2012-01-10 07:01:05 EST
(In reply to comment #40)
> Your heuristic to inherit from a resource-free Closeable and not override
> close is a good one, but I decided to not implement *any* heuristic of
> this kind.
I vote for waiting on this.
- I have not seen too many practical cases for this.
- If we decide to make the white lists configurable by the user, then the small number of such scenarios can be taken care of there.

Stephan, you may also want to start a topic branch for this (and similar bugs) which involve a number of review cycles. Note that the branch name convention to be followed is "<committerid>/branchname", see bug 362363.
Comment 44 Satyam Kandula CLA 2012-01-10 08:07:11 EST
I haven't got hold of the changes as yet. I am looking at the old code also to understand. So, here are some minor comments which includes old code too. Hope that's ok. 
 1. SingleNameReference.java - no change but there is a copyright year change. 
 2. I believe ReferenceBinding#applyCloseableWhiteLists should be optimized for OTHER_WRAPPER_CLOSEABLES. The way I see this is that all the types which are in the list are returned quickly than the ones which are not! All the types will be searched for atleast in the OTHER_WRAPPER_CLOSEABLES. I believe this could be improved. 
 - Should the following case report a resource warning 
    void foo( InputStream input) throws IOException {
	FileInputStream input1  = (FileInputStream)input;
        System.out.println(input1.read());
        input.close();
    }
 3. Method names could be better:
    - FakedTrackingVariable#isAutoCloseable() now looks for closeable too.
    - FakedTrackingVariable#analyseCloseableAllocationArgument(...) should probably be find...(...)
 4. Formatting: I found two formatting styles a different from much of the JDT/Core code. I should tell that there are places which don't follow this style, but ... :) 
    - if statements with only one statements are either written as 
           if(condition) statement or 
           if(condition) {
              statement
           }
           and not 
           if (condition)
              statement
       They are many places I see in this code which uses the latter style. 
      -Methods in a class are generally sorted. I don't see this in FakedTrackingVariable. If you change the formatting now, diff will again become difficult and hence I would recommend not changing it now, but please keep in mind for the new types you create.
  5.Whenever new tracking variable is added through BlockScope#registerTrackingVariable, the MethodScope#analysisIndex is not getting added. As of now, there is no impact as this happens only during analysis and analysisIndex is updated only during resolving, but isn't it a good  idea to update that too?
Comment 45 Satyam Kandula CLA 2012-01-10 09:14:22 EST
>  2. I believe ReferenceBinding#applyCloseableWhiteLists should be optimized for
> OTHER_WRAPPER_CLOSEABLES. The way I see this is that all the types which are in
> the list are returned quickly than the ones which are not! All the types will
> be searched for atleast in the OTHER_WRAPPER_CLOSEABLES. I believe this could
> be improved.
   Please ignore this, I see that this is getting called only when it extends closeable or Autocloseable and hence this is OK.
Comment 46 Stephan Herrmann CLA 2012-01-10 09:22:36 EST
(comment crossed with your latest, submitting as-is anyway)

(In reply to comment #44)
> I haven't got hold of the changes as yet. I am looking at the old code also to
> understand. So, here are some minor comments which includes old code too. Hope
> that's ok. 

Sure, just ask.


>  1. SingleNameReference.java - no change but there is a copyright year change. 

oops, seems like I undid some intermediate changes up-to a clean state and
then the update-copyright-tool re-added its change on save :-/
I'll revert that.

>  2. I believe ReferenceBinding#applyCloseableWhiteLists should be optimized for
> OTHER_WRAPPER_CLOSEABLES. The way I see this is that all the types which are in
> the list are returned quickly than the ones which are not! All the types will
> be searched for atleast in the OTHER_WRAPPER_CLOSEABLES. I believe this could
> be improved.

You're right. How much effort we put into optimizing this algorithm depends
on how many types we have in OTHER_WRAPPER_CLOSEABLES. Initially I had ONE,
I'd say for the current list of 5 it is still acceptable (note that only
closeable types will reach here). Should the list grow we should certainly
do some smarter lookup.

>  - Should the following case report a resource warning 
>     void foo( InputStream input) throws IOException {
>     FileInputStream input1  = (FileInputStream)input;
>         System.out.println(input1.read());
>         input.close();
>     }

Good point. Yes, we want to identify input and input1 (one branch in my
implementation still misses to unwrap the cast expression). This will be
easily fixed. Secondly, there's some interaction with input being a 
parameter. I had hoped we could avoid tracking variables for parameters
(assuming the current method is not responsible for closing), but your
case shows we need a tracking variable but start with a status 
indicating that no warnings should be raised. It seems REPORTED would
be a suitable mark here.

>  3. Method names could be better:
>     - FakedTrackingVariable#isAutoCloseable() now looks for closeable too.

I kept confusing myself by looking how Closeable extends AutoCloseable, but 
only in 1.7 of course, so right, I guess isAnyCloseable() should be better.

>     - FakedTrackingVariable#analyseCloseableAllocationArgument(...) should
> probably be find...(...)

If we accept that the "AllocationArgument" part can remain implicit by way
of the method arguments 3 & 4, we can say "findCloseTracker". And then I'll
make that method private so we're sure its only used in a context where we
know what a closeTracker is :)

>  4. Formatting: I found two formatting styles a different from much of the
> JDT/Core code. I should tell that there are places which don't follow this
> style, but ... :) 
>     - if statements with only one statements are either written as 
>            if(condition) statement or 
>            if(condition) {
>               statement
>            }
>            and not 
>            if (condition)
>               statement
>        They are many places I see in this code which uses the latter style.

I thought I had seen sufficiently many occurrences of the latter style to
conclude that this is accepted JDT/Core style :)
Just looking at FakedTrackingVariable, strictly adhering to the second style
will add almost 30 lines of insignificant code, which IMHO don't add for the
readability but just make me scroll more.
Now, if the rest of the team feels uneasy about the two-lines style,
I can certainly avoid it (after having expressed my dissent :)) 
Should I?
Will we reformat existing occurrences of this style when we touch such code?

>       -Methods in a class are generally sorted. I don't see this in
> FakedTrackingVariable. If you change the formatting now, diff will again become
> difficult and hence I would recommend not changing it now, but please keep in
> mind for the new types you create.

I'm aware of this and yes I know I'm a bit lazy here, sorry. OTOH, while
coding it is much more important for me to keep related methods next to each
other. Sometimes I try to reconcile the alphabetic and the semantical order
by choosing names with common prefixes. Actually the name
analyseCloseableAllocationArgument is an example for that. So how do you
guys cope with this conflict?

>   5.Whenever new tracking variable is added through
> BlockScope#registerTrackingVariable, the MethodScope#analysisIndex is not
> getting added. As of now, there is no impact as this happens only during
> analysis and analysisIndex is updated only during resolving, but isn't it a
> good  idea to update that too?

OK, I can say:
  	outerMethodScope.analysisIndex += (outerMethodScope.trackVarCount++);
	return outerMethodScope.analysisIndex;
or even better:
	return outerMethodScope.analysisIndex++;
That means, we can actually avoid the field trackVarCount, nice!
Comment 47 Stephan Herrmann CLA 2012-01-10 13:11:03 EST
Created attachment 209276 [details]
incremental changes

This patch captures the changes I made in reaction to comment 44.

> >  1. SingleNameReference.java - no change but there is a copyright year change. 

After this got me into git-trouble, I think I've resolved this now in my
local branch.
 
> >  - Should the following case report a resource warning 
> >     void foo( InputStream input) throws IOException {
> >     FileInputStream input1  = (FileInputStream)input;
> >         System.out.println(input1.read());
> >         input.close();
> >     }

test (plus varaints thereof) added as test063d()

> Good point. Yes, we want to identify input and input1 (one branch in my
> implementation still misses to unwrap the cast expression). This will be
> easily fixed.

Done, see FTV#getCloseTrackingVariable()

> Secondly, there's some interaction with input being a 
> parameter. I had hoped we could avoid tracking variables for parameters
> (assuming the current method is not responsible for closing), but your
> case shows we need a tracking variable but start with a status 
> indicating that no warnings should be raised. It seems REPORTED would
> be a suitable mark here.

To avoid confusion I introduced a new bit OBTAINED_FROM_OUTSIDE and
consistently use this for values obtained as method argument or from
a field read. Otherwise I resolved the issue as described.
 
> >  3. Method names could be better:
> >     - FakedTrackingVariable#isAutoCloseable() now looks for closeable too.
> 
> I kept confusing myself by looking how Closeable extends AutoCloseable, but 
> only in 1.7 of course, so right, I guess isAnyCloseable() should be better.

Done.

> >     - FakedTrackingVariable#analyseCloseableAllocationArgument(...) should
> > probably be find...(...)
> 
> If we accept that the "AllocationArgument" part can remain implicit by way
> of the method arguments 3 & 4, we can say "findCloseTracker". And then I'll
> make that method private so we're sure its only used in a context where we
> know what a closeTracker is :)

Done.
 
> >   5.Whenever new tracking variable is added through
> > BlockScope#registerTrackingVariable, the MethodScope#analysisIndex is not
> > getting added. As of now, there is no impact as this happens only during
> > analysis and analysisIndex is updated only during resolving, but isn't it a
> > good  idea to update that too?
> 
> OK, I can say:
>       outerMethodScope.analysisIndex += (outerMethodScope.trackVarCount++);
>     return outerMethodScope.analysisIndex;
> or even better:
>     return outerMethodScope.analysisIndex++;
> That means, we can actually avoid the field trackVarCount, nice!

Done (as per the last and cleanest option).

I also added a test resembling an example found in the p2 sources: test61m.
By means of the one relevant change in handleResourceAssignment()
we can also improve here (was: "is never closed" and has been softened to
"may not be closed"). For the remaining warning in this test: Detecting that 
a method call actually creates a wrapper might be nice but is beyond the 
scope of this bug, I'd say.
Comment 48 Srikanth Sankaran CLA 2012-01-10 19:06:50 EST
(In reply to comment #46)
> >  4. Formatting: I found two formatting styles a different from much of the

> Now, if the rest of the team feels uneasy about the two-lines style,
> I can certainly avoid it (after having expressed my dissent :)) 
> Should I?

In future, yes please.
Comment 49 Satyam Kandula CLA 2012-01-11 03:29:24 EST
Here are some more comments, again all minor. I am not done yet! 
- Tests should probably be at a different place than in TryWithResourcesTest as these run only on Java7.
- isAutoCloseable() is redundant in preConnectTrackerAcrossAssignment: There is a place from Assignment this gets called even if null, so may be a non-null check could be good enough! 
- Only the first argument of an allocation expression is checked for the wrapped logic. Is this because we have seen these pattern ony in the first arguments?
- If the type is in the whitelist but if the argument is not closeable, the closeable is not being tracked. Is there a reason? I didn't look at the complete whitelist completley, but found one case with PrintWriter
        void foo() throws FileNotFoundException {
		PrintWriter input1  = new PrintWriter("abc.txt");
		input1.write(1);
	}
I am fine to err in this side, but just wanted to bring this to your attention  
- this.trackingVariables.size() could be a variable  in BlockScope#checkUnclosedCloseables(...)
Comment 50 Satyam Kandula CLA 2012-01-11 06:11:19 EST
Some more.. 
- Return statement is not being tracked for wrapped. An incorrect error is getting reported. 
  InputStream foo() throws IOException {
        File file = new File("somefil");
        FileInputStream fileStream  = new FileInputStream(file);
        BufferedInputStream bis = new BufferedInputStream(fileStream);   
        return fileStream;
    }
- Isn't the check for BitWrapperCloseable in markPassedToOutside better done at the call site? It doesn't make a difference, IMHO that is better. 
- WRAPPED flag not being part of flowinfo is not able to take into account of scopes.Take the example of this. bis in the given example is not really closed, but not reported.
   void foo() throws IOException {
        File file = new File("somefil");
        FileInputStream fileStream  = new FileInputStream(file);
        BufferedInputStream bis = new BufferedInputStream(fileStream);   
        if (bar()) {
        	BufferedInputStream doubleWrap = new BufferedInputStream(bis);
        	doubleWrap.close();
        }
    }
    boolean bar() {
	return false;
    }
Comment 51 Stephan Herrmann CLA 2012-01-11 20:54:25 EST
(In reply to comment #49)
> Here are some more comments, again all minor. I am not done yet! 
> - Tests should probably be at a different place than in TryWithResourcesTest as
> these run only on Java7.

Yes (except that a few would then need to explicitly check compliance,
because they expect messages like
  "Resource \'input\' should be managed by try-with-resource\n"
which is only flagged at 1.7).

Any suggestion for a better place? Maybe FlowAnalysisTests?


> - isAutoCloseable() is redundant in preConnectTrackerAcrossAssignment: There is
> a place from Assignment this gets called even if null, so may be a non-null
> check could be good enough! 

You mean "rhs.resolvedType != TypeBinding.NULL", right?
I can do that, which means I should document the precondition of this
method, because otherwise this check will look pretty strange.

> - Only the first argument of an allocation expression is checked for the
> wrapped logic. Is this because we have seen these pattern ony in the first
> arguments?

Exactly.

> - If the type is in the whitelist but if the argument is not closeable, the
> closeable is not being tracked. Is there a reason? I didn't look at the
> complete whitelist completley, but found one case with PrintWriter
>         void foo() throws FileNotFoundException {
>         PrintWriter input1  = new PrintWriter("abc.txt");
>         input1.write(1);
>     }
> I am fine to err in this side, but just wanted to bring this to your attention  

Good catch. When I wrote that code I mark it with:
  // remove unnecessary attempts (wrapper has no relevant inner)
but your example proves that I should rather treat it as a normal
resource, not as a wrapper then.

> - this.trackingVariables.size() could be a variable  in
> BlockScope#checkUnclosedCloseables(...)

sure.
Comment 52 Stephan Herrmann CLA 2012-01-11 21:23:53 EST
(In reply to comment #50)
> Some more.. 
> - Return statement is not being tracked for wrapped. An incorrect error is
> getting reported. 
>   InputStream foo() throws IOException {
>         File file = new File("somefil");
>         FileInputStream fileStream  = new FileInputStream(file);
>         BufferedInputStream bis = new BufferedInputStream(fileStream);   
>         return fileStream;
>     }

Interesting pattern :)
Let's see what I can do.. no promise yet.

> - Isn't the check for BitWrapperCloseable in markPassedToOutside better done at
> the call site? It doesn't make a difference, IMHO that is better. 

Are you saying this, because only one call site actually passes an
allocatedType? I was trying to keep the call sites clean, but since it
is only one I can push this out again.

> - WRAPPED flag not being part of flowinfo is not able to take into account of
> scopes.Take the example of this. bis in the given example is not really closed,
> but not reported.
>    void foo() throws IOException {
>         File file = new File("somefil");
>         FileInputStream fileStream  = new FileInputStream(file);
>         BufferedInputStream bis = new BufferedInputStream(fileStream);   
>         if (bar()) {
>             BufferedInputStream doubleWrap = new BufferedInputStream(bis);
>             doubleWrap.close();
>         }
>     }
>     boolean bar() {
>     return false;
>     }

Yes, some parts of the analysis are not aware of branching.
I mentioned in previous comments that complex patterns of assigning
resources to locals on only some branches etc. can not be captured
by my approach. I'll have to think if I can push the limits for this
example. I don't think extending FlowInfo for such corner cases is a
good idea. OTOH, a false negative is a pity. I should probably let
markClose() propagate info to inner resources, and then avoid checking
WRAPPED, but that alone doesn't do the trick. Let's see ...
Comment 53 Satyam Kandula CLA 2012-01-12 00:46:45 EST
Here are some more comments:  Stephan, we can open separate bugs if necessary. 
- In twr, the resource is being removed from tracking. Shouldn't the right thing to do is mark as closed. Right now, it doesn't seem to be a problem, but if you fix the 'PrinteWriter' example, this may become important. 
- may be out of scope of this bug but I get a 'potential resource warning' for this. Is this expected?
	void foo() throws IOException {
		Object input1  =  bar();
        }
	private FileInputStream bar() {
		return null;
	}
- AllocationExpression's closeTracker is not getting null'd.  Is there a way, these can be null'd. 
- Getting a wrong error for 
    class Z {
	FileInputStream input1;
	public void foo() throws IOException {
		FileInputStream input = input1;
		input = new FileInputStream("adfafd");
		input.close();		
	}
    }
Comment 54 Satyam Kandula CLA 2012-01-12 00:53:04 EST
(In reply to comment #51)
> Any suggestion for a better place? Maybe FlowAnalysisTests?
I think a separate file is better.

> You mean "rhs.resolvedType != TypeBinding.NULL", right?
> I can do that, which means I should document the precondition of this
> method, because otherwise this check will look pretty strange.
Yes, you are right.
Comment 55 Satyam Kandula CLA 2012-01-12 00:59:46 EST
(In reply to comment #52)
> Are you saying this, because only one call site actually passes an
> allocatedType? I was trying to keep the call sites clean, but since it
> is only one I can push this out again.
Yes, that is the main reason, but I thought that made more sense. I understand the call sites could be clean, but some how I felt doing the check out could be cleaner. The decision is yours :).
Comment 56 Stephan Herrmann CLA 2012-01-12 08:40:12 EST
Created attachment 209373 [details]
incremental changes 2

This incremental patch includes the following changes:

(In reply to comment #49)
> - Tests should probably be at a different place than in TryWithResourcesTest as
> these run only on Java7.

I created a new class ResourceLeakTests into which I moved all of
test056* and test06[1-3]*. For some of the tests this required specifying
different expectations (specif. the t-w-r warning), and some only work in
1.5+ etc. While doing the move I also performed a white space cleanup.
While this creates some change noise I hope this is acceptable for tests.
(I'll attach just the new test file in a minute for your convenience).

> - isAutoCloseable() is redundant in preConnectTrackerAcrossAssignment: There is
> a place from Assignment this gets called even if null, so may be a non-null
> check could be good enough! 

Done.

> - If the type is in the whitelist but if the argument is not closeable, the
> closeable is not being tracked. Is there a reason? I didn't look at the
> complete whitelist completley, but found one case with PrintWriter
>         void foo() throws FileNotFoundException {
>         PrintWriter input1  = new PrintWriter("abc.txt");
>         input1.write(1);
>     }
> I am fine to err in this side, but just wanted to bring this to your attention  

Added (failing) test061n() -> need more work.

> - this.trackingVariables.size() could be a variable  in
> BlockScope#checkUnclosedCloseables(...)

done.

(In reply to comment #50)
> - Isn't the check for BitWrapperCloseable in markPassedToOutside better done at
> the call site? It doesn't make a difference, IMHO that is better. 

done
Comment 57 Stephan Herrmann CLA 2012-01-12 08:43:12 EST
Created attachment 209374 [details]
ResourceLeakTests.java

new test file.
Comment 58 Stephan Herrmann CLA 2012-01-12 09:08:20 EST
(In reply to comment #53)
> Here are some more comments:  Stephan, we can open separate bugs if necessary. 
> - In twr, the resource is being removed from tracking. Shouldn't the right
> thing to do is mark as closed. Right now, it doesn't seem to be a problem, but
> if you fix the 'PrinteWriter' example, this may become important. 

to be determined once I work on the remaining issues.

> - may be out of scope of this bug but I get a 'potential resource warning' for
> this. Is this expected?
>     void foo() throws IOException {
>         Object input1  =  bar();
>         }
>     private FileInputStream bar() {
>         return null;
>     }

This works exactly as intended. Just rename "bar" to "createInput" and
you would most likely complain if the compiler doesn't complain :)

> - AllocationExpression's closeTracker is not getting null'd.  Is there a way,
> these can be null'd.

Not an easy one. In case the alloc is embedded in an assignment it gets
collected, but "in the event it does NOT get collected by an assignment"
is not a good trigger. I could remove in on the next pass (generateCode),
but that wouldn't help much I'd say. OTOH, it doesn't seem to hurt, right?

> - Getting a wrong error for 
>     class Z {
>     FileInputStream input1;
>     public void foo() throws IOException {
>         FileInputStream input = input1;
>         input = new FileInputStream("adfafd");
>         input.close();        
>     }
>     }

I get 
   Resource leak: \'input\' is not closed at this location,
should be only potential since obtained from a field.
I'll take a look - should be easy.

For now I will focus on those issues where a warning is missing:
comment 49 and comment 50 second example. We shouldn't filter too much!
Comment 59 Stephan Herrmann CLA 2012-01-12 10:03:57 EST
Created attachment 209384 [details]
incremental changes 3

(In reply to comment #58)
> (In reply to comment #53)
> > - Getting a wrong error for 
> >     class Z {
> >     FileInputStream input1;
> >     public void foo() throws IOException {
> >         FileInputStream input = input1;
> >         input = new FileInputStream("adfafd");
> >         input.close();        
> >     }
> >     }
> 
> I get 
>    Resource leak: \'input\' is not closed at this location,
> should be only potential since obtained from a field.

Correction: should indeed be no warning.

> I'll take a look - should be easy.

Indeed, fix is simple (attached).
Comment 60 Stephan Herrmann CLA 2012-01-12 16:00:44 EST
Created attachment 209409 [details]
incremental change 4

Hm, maybe indeed we should have taken some of this to a new bug,
and maybe I should have pushed this to a public feature branch.
Should I still do that?

This delivery fixes comment 50 part 2 by completely getting rid of the
flag WRAPPER. This flag implemented a heuristic to avoid irrelevant
warnings against wrapper resources, but this part, too, is now computed
with more precision. This required some more propagating information up
and down the links:

FTV#markClose() pushes info into the chain of innerTrackers.

reportError(..) has more fine grained control to avoid redundant reporting
without letting a more severe issue be masked by a minor one.

Finally, during BlockScope#checkUnclosedCloseables() I need to ensure that
track variables are iterated in correct order: outer resources before their
inners, so we can mark inners as reported when we report against an outer.
This requires a back link FTV#outerTracker (inverse of FTV#innerTracker)
and changed the loop structure from a for-loop to picking elements from a set
until it's empty (sorry this spoils the loop optimization we recently did).

After fixing the new test061o(), the existing test061f() was broken and it
showed that we had been lucky on that one. Now I was faced with fact that
try-finally statements are actually analyzed finally-first!
  InputStream stream = null;
  BufferedReader reader = null;
  try {
      stream = url.openStream();
      reader = new BufferedReader(new InputStreamReader(stream));
  } finally {
      reader.close();
  }
At the close() call we want to propagate the close-info into the inner
resources incl. 'stream'. HOWEVER, when looking at the close call we don't
even know about the wrapper-chain because the try block hasn't been 
analyzed yet! So 'stream' was again flagged as leaking.
  
The full solution would be to chain all resource information through 
FlowContext and subclasses and postpone the whole issue to Eclipse 3.9+.
That would be investing to much effort to a minor issue.

To shortcut this I let FTV#analyseCloseableAllocation(..) inject info from
the finally block back into newly created wrappers.
Now, if the try block re-configures the resources (re-assignments,
creating more wrappers) this approach will produce imprecise results.
But I don't really want to go any further.

Other changes in the patch became necessary in order to fix intermediate
regressions, but those fixes are essentially straight-forward.
Comment 61 Satyam Kandula CLA 2012-01-13 07:32:10 EST
I haven't finished the last patch yet - I will try to finish this latter today. Please feel free to take out any issue as another bug. 
For now, I have only one comment for the code:
 - AllocationExpression#analyseCode: Pulling the hasTypeBit() check outside the for loop could be nice.
Comment 62 Satyam Kandula CLA 2012-01-13 07:44:54 EST
Here are couple of failures I found now
1.  Getting an error for this
     void foo() throws IOException {
	File file = new File("somefil");
        FileInputStream fileStream  = new FileInputStream(file);
	BufferedInputStream bis = new BufferedInputStream(fileStream);
	bis = null;
	fileStream.close();
     }
2. Minor error: Error is being reported at the first line, it would be good to have it in the third line. 
        void foo( FileInputStream input) throws IOException {
		FileInputStream input1 = new FileInputStream("abc");
		input1.close();
		input1 = new FileInputStream("abc");
	}
Comment 63 Stephan Herrmann CLA 2012-01-13 09:14:48 EST
(In reply to comment #61)
> Please feel free to take out any issue as another bug. 

The version I have in my workspace looks pretty promising, so I think
all examples listed in this bug can be covered by one big patch.
I'll post another update shortly.

I've filed bug 368546 to track remaining false positives.
Comment 64 Stephan Herrmann CLA 2012-01-13 10:05:57 EST
(In reply to comment #62)
> Here are couple of failures I found now
> [..]
> 2. Minor error: Error is being reported at the first line, it would be good to
> have it in the third line. 
>         void foo( FileInputStream input) throws IOException {
>         FileInputStream input1 = new FileInputStream("abc");
>         input1.close();
>         input1 = new FileInputStream("abc");
>     }

I agree, it would be good, but it's not possible with the current approach:
we report against a re-assignment only if the old value was not closed,
however, the old input1 is closed properly.
When we conclude that a resource is *never* closed we always report it
against the first location where a resource was assigned to a given variable.
We simply don't have the information which assignment brings the leaking
instance (could be many potential locations in a branching structure!).
Sorry -> wontfix.
Comment 65 Stephan Herrmann CLA 2012-01-13 10:40:54 EST
Created attachment 209457 [details]
incremental changes 5

This patch completes the changes started in comment 60.
That strategy change broke a few things and analysis has become more
aggressive, so some issues surfaced that previously were hidden.

Changes included in this update:

Passing more information up-and-down like
- FTV#globalClosingState from finally-block into try-block
- FTV#markPassedToOutside also loops into inners

Carefully construct the order in which BlockScope#checkUnclosedCloseables
processes tracking vars:
- process wrappers before their inners
- respect several situations of wrappers and inners defined in different scopes
See FTV#pickVarForReporting for details.
The effect is that now we can safely suppress any reports against inners
if their wrappers have been closed, without needing the bogus bit WRAPPER
that was removed in incremental change 4.

Better evaluate the bits REPORTED_POTENTIAL_LEAK, REPORTED_DEFINITIVE_LEAK
- at the same level (each invocation of BlockScope#checkUnclosedCloseables)
  avoid duplicate reporting of wrappers and inners
- accumulate these flags from invocations to FTV#reportError
- but don't let errors against an error location hide errors against
  other locations
- reset this information at the end for a fresh start at the next level

Includes a few more tests modelled from real world bits in the Eclipse SDK.
Comment 66 Stephan Herrmann CLA 2012-01-13 11:04:19 EST
Created attachment 209460 [details]
incremental changes 6

(In reply to comment #62)
> Here are couple of failures I found now
> 1.  Getting an error for this
>      void foo() throws IOException {
>     File file = new File("somefil");
>         FileInputStream fileStream  = new FileInputStream(file);
>     BufferedInputStream bis = new BufferedInputStream(fileStream);
>     bis = null;
>     fileStream.close();
>      }

Just when I was going to say "no" to this request I found a fairly simple
way to disassemble a wrapper chain when the wrapper is being dropped.

Two caveats: 
 - this slightly changed the reporting in test063a, but I think that's OK
 - the trick only works in a flat structure - if the assignment happens in a
   different scope than the definition of the resource, then I can do nothing,
   because I cannot create a "conditional wrapper chain" :-/
Comment 67 Stephan Herrmann CLA 2012-01-13 11:33:12 EST
Created attachment 209464 [details]
incremental change 7

(In reply to comment #49)
> - If the type is in the whitelist but if the argument is not closeable, the
> closeable is not being tracked. Is there a reason? I didn't look at the
> complete whitelist completley, but found one case with PrintWriter
>         void foo() throws FileNotFoundException {
>         PrintWriter input1  = new PrintWriter("abc.txt");
>         input1.write(1);
>     }
> I am fine to err in this side, but just wanted to bring this to your attention  
> - this.trackingVariables.size() could be a variable  in
> BlockScope#checkUnclosedCloseables(...)

This is the last one I planned to address (test061n failed until now)

Wrapper allocations without a proper inner resource are now treated like
normal resources.

I'm currently re-running all tests, will scan all comments whether anything
got forgotten and will post my results together with a single flattened
patch.
Comment 68 Stephan Herrmann CLA 2012-01-13 12:55:16 EST
(In reply to comment #53)
> Here are some more comments:  Stephan, we can open separate bugs if necessary. 
> - In twr, the resource is being removed from tracking. Shouldn't the right
> thing to do is mark as closed. Right now, it doesn't seem to be a problem, but
> if you fix the 'PrinteWriter' example, this may become important. 

Interestingly this basic example is correctly silent:

    PrintWriter writer = new PrintWriter(\"filename\");
    try (BufferedWriter bw = new BufferedWriter(writer)) {
	bw.write(1);
    }

But a more involved variant is missing a warning:

    PrintWriter writer = new PrintWriter("filename");
    if (b) {
        try (BufferedWriter bw = new BufferedWriter(writer)) {
            bw.write(1);
        }
    }

Will add this as a disabled test case and add a note to bug 368546.
Comment 69 Stephan Herrmann CLA 2012-01-13 14:09:12 EST
Created attachment 209472 [details]
incremental changes 8

From collecting all left-over items here's my final update for now:

(In reply to comment #61)
>  - AllocationExpression#analyseCode: Pulling the hasTypeBit() check outside the
> for loop could be nice.

Done.

(In reply to comment #50)
> - Return statement is not being tracked for wrapped. An incorrect error is
> getting reported. 
>   InputStream foo() throws IOException {
>         File file = new File("somefil");
>         FileInputStream fileStream  = new FileInputStream(file);
>         BufferedInputStream bis = new BufferedInputStream(fileStream);   
>         return fileStream;
>     }

I was removing the tracker for 'fileStream' from the scope, but this left
'bis' without information about this return statement. The fix is in 2 steps:
- change ReturnStatement to saying markPassedToOutside(..)
- add check to BlockScope#checkUnclosedCloseables whether a tracker
  being analyzed equals the return value, considering also inners.
  If so, mark as reported to also prevent inners from being flagged.

I had to slightly adjust one expected result in NullReferenceTests.
The previous version was actually better, but the current outcome is a
direct result of weak flow information coming out of a try statement.
Not much I can do.

Added tests
- a forgotten test from coment 66
- tests from comment 68
- test for the above example (from comment 50)
Comment 70 Stephan Herrmann CLA 2012-01-13 16:17:57 EST
Created attachment 209482 [details]
Tests & fix v1.0

After final editorial changes and another full test run this is my
release candidate for now. Functionally this is equivalent to the sum
of all incremental changes.

Thanks, Satyam, for all your comments so far. I think with our joined
desire for perfection we morphed a set of heuristics into a pretty sharp
analysis :)

I hope my set of incremental changes wasn't too much a moving target for
your review. Let me know whether you see the need for further changes.
Comment 71 Srikanth Sankaran CLA 2012-01-13 21:00:07 EST
(In reply to comment #70)
> Created attachment 209482 [details]
> Tests & fix v1.0
> 
> After final editorial changes and another full test run this is my
> release candidate for now. Functionally this is equivalent to the sum
> of all incremental changes.

Satyam, I agree with the plan to treat this patch as the release candidate.
Unless your further review and verification uncovers ship stopper issues,
we'll address them via follow up defects post M5.

Stephan may be offline Monday & Tuesday. So you may have to release it
on his behalf - Thanks!
Comment 72 Satyam Kandula CLA 2012-01-14 12:44:52 EST
Stephan, 
I just had a customary look now and will try to complete the review tomorrow. I saw one typo as of now. 
In BlockScope#checkUnclosedCloseables():1059
I believe it should be trackingVariables.get(i) instead of trackingVariables.get(0).
Comment 73 Stephan Herrmann CLA 2012-01-14 13:04:36 EST
(In reply to comment #72)
> Stephan, 
> I just had a customary look now and will try to complete the review tomorrow. I
> saw one typo as of now. 
> In BlockScope#checkUnclosedCloseables():1059
> I believe it should be trackingVariables.get(i) instead of
> trackingVariables.get(0).

Of coures, well spotted, eagle-eye!

[Shouldn't the compiler be able to detect such stupid typos? :) ]
Comment 74 Satyam Kandula CLA 2012-01-15 02:12:53 EST
Couple of minor comments
 - FakedTrackingVariable#findCloseTracker(): allocation is not used. 
 - May be a good idea to add a small comment in TWRTest that test056xx has been moved to new test. 

With this, I conclude the review :). +1 for the patch. Please release the patch if you can. If you are not able to today, I can release it tomorrow. 

Stephan, Thanks very much for your explanations and for taking care of all the comments very quickly.
Comment 75 Stephan Herrmann CLA 2012-01-15 09:28:37 EST
After applying final polish (see comment 74) I've pushed 
commit 8d45cb26fc5ad244f93e8632d761d46ad4a120cf
which resolves this issue.
Comment 76 Satyam Kandula CLA 2012-01-16 08:07:41 EST
(In reply to comment #75)
> After applying final polish (see comment 74) I've pushed 
> commit 8d45cb26fc5ad244f93e8632d761d46ad4a120cf
> which resolves this issue.
I want to add one point. This patch doesn't change the default for this problem and I think it is better to be left like that for this release. We could change to a warning in 3.8M1.
Comment 77 Stephan Herrmann CLA 2012-01-16 08:42:52 EST
(In reply to comment #76)
> (In reply to comment #75)
> > After applying final polish (see comment 74) I've pushed 
> > commit 8d45cb26fc5ad244f93e8632d761d46ad4a120cf
> > which resolves this issue.
> I want to add one point. This patch doesn't change the default for this problem
> and I think it is better to be left like that for this release. We could change
> to a warning in 3.8M1.

I was going to ask about this.

I'd propose to await progress in bug 368546. If I can resolve that bug
during milestone X, maybe after positive experience we can change the default
early during milestone X+1? We should certainly coordinate with Kim to
clarify which version will be used to build the SDK at what point in time.

Doing the change for 3.8M1 is a good one :)
Comment 78 Dani Megert CLA 2012-01-16 08:54:09 EST
> We should certainly coordinate with Kim to
> clarify which version will be used to build the SDK at what point in time.

Kim normally switches to the latest milestone compiler after the milestone. At any rate, the switch should never happen close to a milestone because the switch can
- result in new warnings/errors being detected
- different bytecode for unchanged source which causes comparator test failures
Comment 79 Satyam Kandula CLA 2012-01-16 09:19:26 EST
(In reply to comment #77)

> > and I think it is better to be left like that for this release. We could change
> > to a warning in 3.8M1.

> Doing the change for 3.8M1 is a good one :)
Ofcourse you caught me :(, but for the record, I meant 3.9M1.
Comment 80 Deepak Azad CLA 2012-01-16 12:02:03 EST
Stephan, do you know what is the percentage of false positives now? If it is even 20-25% I would toggle the default in the beginning of M6. In any case I think we should aim latest for M7 to toggle the default. M7 is supposed to be the 'polish' milestone, we can nudge people to fix resource leaks during that time.
Comment 81 Srikanth Sankaran CLA 2012-01-16 19:43:12 EST
(In reply to comment #79)

> Ofcourse you caught me :(, but for the record, I meant 3.9M1.

+1
Comment 82 Ayushman Jain CLA 2012-01-24 09:52:45 EST
Verified using build I20120122-2000