Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 367566 - In try-with-resources statement close() method of resource is not called
Summary: In try-with-resources statement close() method of resource is not called
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.7.1   Edit
Hardware: PC Windows XP
: P3 critical (vote)
Target Milestone: 3.6.2+J7   Edit
Assignee: Srikanth Sankaran CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-12-27 02:20 EST by Roman Dawydkin CLA
Modified: 2013-08-30 08:49 EDT (History)
6 users (show)

See Also:
daniel_megert: pmc_approved+


Attachments
Test sources (1.46 KB, application/octet-stream)
2011-12-27 02:20 EST, Roman Dawydkin CLA
no flags Details
test & preliminary fix (3.03 KB, patch)
2011-12-27 14:26 EST, Stephan Herrmann CLA
no flags Details | Diff
Alternate patch (6.66 KB, patch)
2012-01-03 06:39 EST, Srikanth Sankaran CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Roman Dawydkin CLA 2011-12-27 02:20:01 EST
Created attachment 208810 [details]
Test sources

close() method is not executed, probably when calling method ends with return statement with condition.
(Produces bytecode is somewhat messy and do not handle all execution paths)
See attached sources for test case.
Code compiled with Oracle javac runs normally.

Tested on Eclipse 3.8M4 and 3.7.1
JDK is 1.7u2

When compiled with Eclipse, output is something like:
  Test.Test()
    Resource.Resource() @150bd4d
  Test.close()
  ERROR: some resources was not closed
   -> test.Resource@150bd4d

When compiled with javac, output is:
  Test.Test()
    Resource.Resource() @12b6651
    Resource.close() @12b6651
  Test.close()
Comment 1 Stephan Herrmann CLA 2011-12-27 14:26:34 EST
Created attachment 208816 [details]
test & preliminary fix

Indeed! The generated code contains a premature ireturn that
bypasses the implicit call to close().

The patch contains a simpler test case and a preliminary fix.
Inside ReturnStatement.analyseCode(..) we didn't recognize that
we are in a context that indeed has a subroutine to be called
before returning, and thus the flag IsReturnedValue was wrongly set.
The flag then cause generating the bogus ireturn.

The patch fixes that by searching also for an enclosing try statement
with resources (which doesn't have an InsideSubRoutineFlowContext
but still needs to call a subroutine).
Comment 2 Roman Dawydkin CLA 2011-12-28 06:25:48 EST
(In reply to comment #1)
> Created attachment 208816 [details]
> test & preliminary fix

Stephan, thank you!
With patch it seems all work good.
I compiled patched org.eclipse.jdt.core bundle for myself and put it into Eclipse plugins folder.
Comment 3 Stephan Herrmann CLA 2011-12-28 07:09:55 EST
(In reply to comment #2)
> (In reply to comment #1)
> > Created attachment 208816 [details]
> > test & preliminary fix
> 
> Stephan, thank you!
> With patch it seems all work good.

Thanks for confirming!
The patch still needs to be reviewed, but we certainly want
this fixed no later than M5.

@Ayush: do you think we should actually have an
InsideSubRoutineFlowContext in this situation, 
or do you consider the location where my patch applies safe?
Comment 4 Srikanth Sankaran CLA 2011-12-31 07:23:52 EST
Stephan, we have a test org.eclipse.jdt.core.tests.compiler.regression.TryWithResourcesStatementTest.test030() that tests for this and asserts that the resource closes do happen.

Have you been able to find out what is special about the current test case that
causes this problem ?
Comment 5 Stephan Herrmann CLA 2011-12-31 09:45:16 EST
(In reply to comment #4)
> Stephan, we have a test
> org.eclipse.jdt.core.tests.compiler.regression.TryWithResourcesStatementTest.test030()
> that tests for this and asserts that the resource closes do happen.
> 
> Have you been able to find out what is special about the current test case that
> causes this problem ?

The difference is:
- the return statement returns a value provided by a binary expression
  of type boolean

The bit that was missing from my explanation in comment 1 is:
Inside BinaryExpression.generateCode(..) we check for ASTNode.IsReturnedValue,
iff set we generate an immediate ireturn for the true-case.
If IsReturnedValue is set in a t-w-r without a finally block we
miss to generate the close() call for the true-case.

The test030 you mention doesn't involve a return value.
Comment 6 Srikanth Sankaran CLA 2012-01-03 06:39:38 EST
Created attachment 208929 [details]
Alternate patch

I didn't find anything particularly wrong with the patch
already proposed, but I like this alternate patch (slightly)
better. This is still under test.

We now recognize the presence of autocloseables in the
picture as an additional case where we cannot abruptly
return while computing the return value. (as is already
done for synchronized block.)

The original patch tends to pass around null values and
has to guard against one case where this passing around
would result in an NPE. So I feel the current patch is
somewhat cleaner.

Stephan, let me know if I have overlooked something.
Comment 7 Srikanth Sankaran CLA 2012-01-03 06:41:34 EST
(In reply to comment #6)
> Created attachment 208929 [details]
> Alternate patch

This patch also includes an additional test.
Comment 8 Stephan Herrmann CLA 2012-01-03 07:28:05 EST
(In reply to comment #6)
> We now recognize the presence of autocloseables in the
> picture as an additional case where we cannot abruptly
> return while computing the return value. (as is already
> done for synchronized block.)

The main difference I see between both patches is whether or not
saveValueNeeded is set, the impact of which I don't immediately understand.
Analogy to a regular finally recommends yes, analogy to synchronized says no.
Hm...

> Stephan, let me know if I have overlooked something.

At a quick glance your patch looks good to me. My patch was more
for checking my theory about the root cause and I wasn't quite
sure about all its side effects.

Please feel free to take the bug if you want to release your patch.
Comment 9 Srikanth Sankaran CLA 2012-01-03 10:24:35 EST
(In reply to comment #8)

> The main difference I see between both patches is whether or not
> saveValueNeeded is set, the impact of which I don't immediately understand.

There is not much really. This boolean short circuits setting of the
ASTNode.IsReturnedValue bit, which we are achieving otherwise anyways.

Released fix and tests via
http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=667b6c6169416d9b79d86e73c3fa9c45930c36a8
for 3.8 M5.

Ayush, could you release these for 3.7.2 and 3.6.2+Java7 streams ? TIA.
Comment 10 Srikanth Sankaran CLA 2012-01-09 10:42:40 EST
Dani, we need to back port this fix too. In some not very
uncommon cases, we will fail to close the resources 
specified in a TWR. Fix is clean IMO.
Comment 11 Dani Megert CLA 2012-01-09 11:47:47 EST
+1 for backport.
Comment 12 Ayushman Jain CLA 2012-01-10 00:38:23 EST
Released in 3.7 maintenance via commit 4bd87a9bbcc7e440b98ccfd3be7628d44517951c
Comment 13 Ayushman Jain CLA 2012-01-10 01:46:41 EST
Released in 3.6.2+Java7 branch via http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=117d4b22e0330a291663c9fe32b87118e24c700b
Comment 14 Dani Megert CLA 2012-01-10 02:48:26 EST
(In reply to comment #13)
> Released in 3.6.2+Java7 branch via
> http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=117d4b22e0330a291663c9fe32b87118e24c700b

Please not that you still need to do the build input manually (as in contrast to 3.7.2), see bug 364676.
Comment 15 Jay Arthanareeswaran CLA 2012-01-19 05:33:03 EST
Verified for 3.7.2 RC2 with build M20120118-0800
Comment 16 Jay Arthanareeswaran CLA 2012-01-24 06:04:22 EST
Verified for 3.8M5 using I20120122-2000
Comment 17 Stephan Herrmann CLA 2013-08-29 11:20:35 EDT
Should this still be verified for 3.6.2+J7 (see target) or is it OK to mark VERIFIED?
Comment 18 Dani Megert CLA 2013-08-30 08:49:24 EDT
(In reply to comment #17)
> Should this still be verified for 3.6.2+J7 (see target) or is it OK to mark
> VERIFIED?

Verified in R3_6_maintenance_Java7.