Project

Profile

Help

Support #4833

closed

Resource leak when using an URIResolver

Added by Philip Helger over 3 years ago. Updated over 3 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
JAXP Java API
Sprint/Milestone:
-
Start date:
2020-11-19
Due date:
% Done:

0%

Estimated time:
Legacy ID:
Applies to branch:
10
Fix Committed on Branch:
Fixed in Maintenance Release:
Platforms:

Description

Hi,

I've been pointed to an issue, that included resources of some Schematrons cannot be deleted after compilations, because the resource is "in use". When debugging through the relevant code pieces, I stumbled upon this code snippet in clas DocumentFN lines 385ff (Saxon-HE Java, 10.3):

        if (source instanceof StreamSource && ((StreamSource)source).getInputStream() == null && ((StreamSource)source).getReader() == null) {
            String uri = source.getSystemId();
 ...
       }

In my scenario ((StreamSource)source).getInputStream() opens a File and returns the respective handle (the same applies of course to ((StreamSource)source).getReader()) as well. As this InputStream is never closed it creates a resource leak.

So please make sure InputStream and Reader are closed if they are opened.

Thanks, Philip

Actions #1

Updated by Michael Kay over 3 years ago

Are you sure? Looking at the source code for StreamSource, it's simply

public InputStream getInputStream() {
        return inputStream;
    }

public Reader getReader() {
        return reader;
    }

so unless you've subclassed StreamSource to do something different, these methods don't attempt to open the stream and should have no such side-effects.

Now, of course it's always possible that we're opening the stream somewhere else, not in the code that you're pointing to as the culprit. In fact the design of StreamSource and URIResolver makes this all quite difficult. As a general rule, we follow the policy that whoever creates a Stream is responsible for closing it after use; that would mean that if your URIResolver creates the Stream then it's responsible for closing it, and of course that doesn't work because the URIResolver API doesn't have a close() method that would enable that to happen.

As a workaround we introduced AugmentedSource, which can wrap around a StreamSource and has a flag pleaseCloseAfterUse. If your URIResolver returns a StreamSource with this flag set, then we will indeed call close() on the InputStream when parsing is done.

We could have chosen to always wrap a StreamSource returned by a URIResolver in an AugmentedSource with this flag set. I'm pretty sure there was a reason we didn't, but I can't remember what the reasoning was. I fear though that if we changed the code to do the close() implicitly, someone's application would almost certainly break.

Actions #2

Updated by Philip Helger over 3 years ago

Hello Michael, Thank you very much for the swift response.

Indeed I am using a subclass of StreamSource that overwrites these two methods.

Using the AugmentedSource is not really an option for me as I am trying to work with the standard API only without explicitly relying on Saxon directly. Also looking at the implementation of AugmentedSource.close which calls ParseOptions.close I am convinced it will not solve my issue:

                StreamSource ss = (StreamSource) source;
                if (ss.getInputStream() != null) {
                    ss.getInputStream().close();
                }
                if (ss.getReader() != null) {
                    ss.getReader().close();
                }

Each call to getInputStream effectively returns a new FileInputStream(file)....

So basically I should only use StreamSource implementations that have a single, fixed InputStream or Reader. Hmmm....

Actions #3

Updated by Michael Kay over 3 years ago

Yes, I think StreamSource has an implicit contract that getInputStream and getReader are side-effect-free methods, and you've broken that contract in your subclass.

Actions #4

Updated by Philip Helger over 3 years ago

Using this assumption, the issue can be closed as "won't fix". Thank you.

Actions #5

Updated by Michael Kay over 3 years ago

  • Tracker changed from Bug to Support
  • Category set to JAXP Java API
  • Status changed from New to Closed
  • Assignee set to Michael Kay

Please register to edit this issue

Also available in: Atom PDF