Skip to content
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

fs streams leak fd on invalid argument #35168

Closed
ronag opened this issue Sep 12, 2020 · 10 comments
Closed

fs streams leak fd on invalid argument #35168

ronag opened this issue Sep 12, 2020 · 10 comments
Labels
fs Issues and PRs related to the fs subsystem / file system.

Comments

@ronag
Copy link
Member

ronag commented Sep 12, 2020

// throws and leaks fd
fs.createReadStream(null, {
  fd,
  start: 'invalid argument'
})
@ronag ronag added the fs Issues and PRs related to the fs subsystem / file system. label Sep 12, 2020
@ronag ronag changed the title fs streams don't close fd on invalid argument fs streams leak fd on invalid argument Sep 12, 2020
@dylanelliott27
Copy link
Contributor

Hi @ronag , I worked out a solution that seems to solve the issue, I just wanted to run my thinking process by you to ensure I am on the right track.

I am catching the error that is thrown from validateInteger, executing fs.close() on the fd variable passed into the ReadStream/WriteStream constructor, then re-throwing the error that was caught.

Let me know if my solution here is incorrect or if you have any advice.

Thanks.

@dylanelliott27
Copy link
Contributor

@ronag Should I be handling the error from fs.close callback in any specific way? Or should I be using the synchronous method

@ronag
Copy link
Member Author

ronag commented Sep 15, 2020

@dylanelliott27 create a PR and we can discuss it there

@AasthaGupta
Copy link
Contributor

@ronag I don't think this is the right problem to be solved at node level but actually, the program using the createReadStream has the fd leak problem. At least considering the snippet you have put in the description.

I went ahead and checked if we are leaking fd in the case when the path argument is valid and the start argument is invalid. Since in that scenario, the caller has no control over the opened file descriptor. But that's not the case either.

And here's what I did to confirm that:

  1. Created a file which can't be opened by the user executing the code
  2. Used following code
const fs = require('fs');

fs.createReadStream("./tmp.txt", {
    start: 'invalid argument'
})

If the file was being read before argument validation then it would have thrown permission denied, but the test code threw the "Invalid argument" error.

Hence we can conclude that node is not leaking fd.

@ronag
Copy link
Member Author

ronag commented Oct 4, 2020

I don't quite follow...

Hence we can conclude that node is not leaking fd.

It is leaking a fd since fs.close is never invoked on the fd if the ReadStream constructor throws. My example is when passing an explicit fd.

@targos
Copy link
Member

targos commented Oct 11, 2020

@ronag There's nothing special about createReadStream. All fs methods that accept a file descriptor do not close it when they throw because of bad arguments. For example fs.write(fd, {wrong: 'object'}) also "leaks" fd.

@ronag
Copy link
Member Author

ronag commented Oct 11, 2020

@ronag There's nothing special about createReadStream.

There is something special... streams take ownership of the fd and closes it, while e.g. fs.write does not.

@ronag
Copy link
Member Author

ronag commented Oct 11, 2020

You could argue either way in regards to what to expect in this specific case. I think it's cleaner if it closes it otherwise you always should wrap createReadStream/createWriteStream into a try/catch with fs.close, which most users simply won't do. Regardless assumptions should preferably be documented.

@targos
Copy link
Member

targos commented Oct 11, 2020

you always should wrap createReadStream/createWriteStream into a try/catch with fs.close

Not necessarily. You are not supposed to pass invalid arguments to createReadStream in the first place. This is a programming error and the reason why asynchronous functions in Node.js can throw synchronous errors in that case. The solution here is to call createReadStream correctly, not to wrap it into a try/catch.

@ronag
Copy link
Member Author

ronag commented Oct 11, 2020

Hm, fair enough.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fs Issues and PRs related to the fs subsystem / file system.
Projects
None yet
Development

No branches or pull requests

4 participants