-
Notifications
You must be signed in to change notification settings - Fork 6.3k
8367561: Getting some "header" property from a file:// URL causes a file descriptor leak #27633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
👋 Welcome back jpai! A progress list of the required criteria for merging this PR into |
❗ This change is not yet ready to be integrated. |
Webrevs
|
@Override | ||
public String getHeaderField(String name) { | ||
initializeHeaders(); | ||
return super.getHeaderField(name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Several header related method implementations in this class have been updated to avoid the super.XXXX()
calls. The super.XXX()
implementation was calling getInputStream()
and ignoring/not using the returned InputStream
. That call to getInputStream()
was a way to initiate a readability check and if the File wasn't readable then it would return a different result compared to when it was readable. The use of getInputStream()
has been replaced by a call to isReadable()
which does the same checks without leaving around a InputStream
instance. Apart from that change, the rest of the code that resided in the super.XXX()
implementation has been literally copy/pasted in these methods to avoid any kind of behavioural change.
Can I please get a review of this change which proposes to fix a file descriptor leak in
sun.net.www.protocol.file.FileURLConnection
?The bug affects all JDK versions since Java 8 through mainline JDK. Furthermore, the issue isn't in any way related to "jar:" URLs or the JAR resources caching involved in the
JarURLConnection
.sun.net.www.protocol.file.FileURLConnection
is ajava.net.URLConnection
. For this issue, the APIs onURLConnection
that are of interest areconnect()
, header related APIs (the getHeaderXXXX(), getLastModified() and similar APIs) andgetInputStream()
.The existing implementation in
FileURLConnection
in itsconnect()
implementation does readability checks on the underlyingFile
instance. If theFile
is a directory then the readability check is done by verifying that aFile.list()
call does not return null. On the other hand, if the File is not a directory, then connect() constructs a temporaryjava.io.FileInputStream
for the File and lets the FileInputStream's constructor implementation do the necessary readability checks. In either case, if the readability checks fail, then an IOException is thrown from this method and the FileURLConnection stays unconnected.One important detail of the implementation in
FileURLConnection.connect()
is that theFileInputStream
that it creates for the regular-file readability check, it keeps it open when it returns fromconnect()
.connect()
itself doesn't return any value, so thisFileInputStream
that was created for readability check remains open without the application having access to it, unless the application calls(File)URLConnection.getInputStream()
. The implementation ofFileURLConnection.getInputStream()
returns this previously constructedInputStream
ifconnect()
had previously suceeded with its readability checks. The application, as usual, is then expected toclose()
thatInputStream
that was returned fromURLConnection.getInputStream()
. This is the "normal" case, where the application at some point calls theURLConnection.getInputStream()
and closes that stream.As noted previously,
URLConnection
has a few other APIs, for example the APIs that provide header values. An example:The issue/leak arises in these cases. Application code constructs a
URLConnection
and invokes these trivial APIs and neither does an explicitconnect()
nor callsgetInputStream()
, because it doesn't have to. In code like this, the implementation ofFileURLConnection
internally in the implementation ofgetLastModified()
and other similar APIs, does aconnect()
. As explained above, the implementation ofconnect()
then creates and leaves around aFileInputStream
after doing readability checks. In this above application code, theInputStream
never reaches the application code nor does it closed, thus leading to the leak.The specification of
URLConnection
states:It can be argued that it seems to expect that the application call
URLConnection.getInputStream()
and then close() it to close the resources, even in the case where it isn't interested in theInputStream
or its contents. But, I think, it's a bit odd to be expecting applications to be doing that, if at all that's what is expected. So the change in this PR proposes to address the leak that can arise when the application never callsURLConnection.getInputStream()
.The change in this PR, keeps the readability checks in the
connect()
method. However, theFileInputStream
that is opened to do the readability check is closed before returning from theconnect()
method. That way, there is noInputStream
lying around. When/if the application callsURLConnection.getInputStream()
then the implementation in that method has been updated to construct and return theFileInputStream
. This does mean that there's a change in behaviour for the following case (I consider it a corner case):Before the changes in this PR, the above scenario would result in the
URLConnection.getInputStream()
returning normally aInputStream
instance (that was cached during the connect() call). The application would then be able to normally/successfully read content from thatInputStream
. With the proposed change in this PR, theURLConnection.getInputStream()
call will throw aFileNotFoundException
, when it attempts to construct theFileInputStream
and noticing that the file doesn't have "read" permission.URLConnection.getInputStream()
is specified to throw anIOException
, so the exception (and its type) itself isn't a problem. It however is still a change in behaviour. Having said that, my opinion is that changing file permissions in between API calls on aURLConnection
is a corner case and I think it might be OK if there is a change in behaviour here (along with a release note maybe), especially since I think the proposed change prevents a leak in a "normal" usage of theURLConnection
APIs in the application code (and also helps the internal implementation inFileURLConnection
to have a more clearly demarcated lifetime for theInputStream
instance).Additional care has been taken to make sure that no other change in behaviour is introduced. 2 new jtreg tests have been introduced. The
FileURLConnStreamLeakTest
is a regression test which reproduces the leak and verifies the fix - several test methods in this test will fail on Windows without the fix and will pass with the fix. TheGetInputStreamTest
is a new test which has been introduced to help improve the coverage of testing for theInputStream
returned from theFileURLConnection
.tier1, tier2 and tier3 tests pass with this change.
Progress
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/27633/head:pull/27633
$ git checkout pull/27633
Update a local copy of the PR:
$ git checkout pull/27633
$ git pull https://git.openjdk.org/jdk.git pull/27633/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 27633
View PR using the GUI difftool:
$ git pr show -t 27633
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/27633.diff
Using Webrev
Link to Webrev Comment