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: ignore fstat errors on user fds in fs.readFile{Sync} #20800

Closed
wants to merge 1 commit into from

Conversation

joyeecheung
Copy link
Member

On Windows fstat cannot be called on std fds. In those cases,
we already know that the fd is not for a regular file and can
just use a list of buffers to store the data.

Also makes sure that we don't close fds provided by users
if we cannot call fstat on them.

Fixes: #19831

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines

Note that this does not actually fix #19831 (comment) (on Windows calling fstat on those fds returns EISDIR..even if errors are intended, EISDIR is a rather odd error for this)

@nodejs-github-bot nodejs-github-bot added the fs Issues and PRs related to the fs subsystem / file system. label May 17, 2018
@joyeecheung
Copy link
Member Author

@joyeecheung

This comment has been minimized.

@joyeecheung
Copy link
Member Author

cc @nodejs/fs

lib/fs.js Outdated
binding.fstat(fd, req);
// On Windows fstat cannot be called on std fds, so just use 0 as its size,
// which would result in a list of buffers to be concatenated
if (isStdFD(fd)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's just Windows, should we be checking process.platform === 'win32' && isStdFD(fd) instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mscdex hmm, yes, it would probably favor the case on non-windows platforms where the stdin is redirected from a regular file.

Copy link
Member Author

@joyeecheung joyeecheung May 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or, the check probably is unnecessary since on Windows fstat still works on stdin if it's redirected. The isUserFd check should already be enough in case of errors.

@joyeecheung
Copy link
Member Author

Updated to just ignore fstat errors on user-provided fds. In cases where the std fds are redirected from regular files, we may still be able to know the size of the buffer to allocate.

CI: https://ci.nodejs.org/job/node-test-pull-request/14928/

@mscdex
Copy link
Contributor

mscdex commented May 17, 2018

I'm confused as to why 0 size is now being forced for all user-supplied file descriptors if this is specifically about stdin/stdout/stderr. Also, if this is only a problem on Windows, I still think we should only be bypassing fstat() on that platform.

@mscdex
Copy link
Contributor

mscdex commented May 17, 2018

Lastly, if this is only a problem in only some situations with stdin/stdout/stderr on Windows, why not just try fstat() first and if it results in an error and is one of stdin/stdout/stderr (and/or the error message is unique enough), only then use 0 for the size and continue?

@joyeecheung
Copy link
Member Author

I'm confused as to why 0 size is now being forced for all user-supplied file descriptors if this is specifically about stdin/stdout/stderr. Also, if this is only a problem on Windows, I still think we should only be bypassing fstat() on that platform.

The size is only assumed 0 when the user-provided fd cannot be fstated. If it cannot actually be read, then there will be an error when the read call happens.

@joyeecheung
Copy link
Member Author

joyeecheung commented May 17, 2018

Lastly, if this is only a problem in only some situations with stdin/stdout/stderr on Windows, why not just try fstat() first and if it results in an error and is one of stdin/stdout/stderr (and/or the error message is unique enough), only then use 0 for the size and continue?

That is more-or-less what this PR does at the moment. Difference is it does not error out right away when fstat returns an error even if the fd is not 0/1/2. If the fd ends up being unreadable, there will be an error when read is invoked.

@mscdex
Copy link
Contributor

mscdex commented May 17, 2018

I still think we should be more strict when enabling this behavior, checking platform, error type, whether it's an std{in,out,err} fd, etc. No matter what I think this should be semver-major.

@joyeecheung
Copy link
Member Author

joyeecheung commented May 17, 2018

I still think we should be more strict when enabling this behavior, checking platform, error type, whether it's an std{in,out,err} fd, etc. No matter what I think this should be semver-major.

I agree but the complexity should probably be best addressed in uv_fs_fstat. For one thing, EISDIR on those fds seems pretty odd.

@mscdex
Copy link
Contributor

mscdex commented May 17, 2018

I'm not so sure that it makes sense to change it in libuv, since reporting a size of 0 but the fd still being readable seems contradictory?

@joyeecheung
Copy link
Member Author

joyeecheung commented May 17, 2018

I'm not so sure that it makes sense to change it in libuv, since reporting a size of 0 but the fd still being readable seems contradictory?

stdin without being directed on non-windows platforms also has size 0 in fstat so that doesn't seem to be an issue. (also, the fact that you can get an EISDIR with fstat is...odd)

@addaleax
Copy link
Member

This might be a silly question, but why are we trying to get the file size in advance anyway? I could imagine it is to save on the # of Buffer allocations, but I don’t think it’s really necessary, right?

@joyeecheung
Copy link
Member Author

joyeecheung commented May 18, 2018

This might be a silly question, but why are we trying to get the file size in advance anyway? I could imagine it is to save on the # of Buffer allocations, but I don’t think it’s really necessary, right?

@addaleax Definitely not a silly question. The size is used to

  1. Throw a ERR_FS_FILE_TOO_LARGE early if it's larger than Buffer.kMaxLength
  2. Allocate the buffer beforehand with the size if it's a regular file
  3. Allocate a list of buffers of kReadFileBufferLength if it's not a regular file (size = 0, which applies to unredirected stdin, which is also set when mode & S_IFREG is 0) and concatenate them when the read ends.

@joyeecheung
Copy link
Member Author

If we want to eliminate the need to know the size beforehand I think we could only go with 3 (always use list of buffers to deal with unknown size), but that adds the overhead of concatenation for the most common cases (reading a regular file)

@joyeecheung joyeecheung changed the title fs: skip fstat on std fds in fs.readFile{Sync} fs: ignore fstat errors on user fds in fs.readFile{Sync} May 18, 2018
@BridgeAR
Copy link
Member

Ping @addaleax

Copy link
Member

@addaleax addaleax left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about the ping (I didn’t block this & my questions had been answered) but LGTM. Still needs a rebase, though. :)

Note that on Windows, calling fstat on std fds that are not redirected returns EISDIR but they can still be read, so we just need to avoid treating them as regular files.

Is that a bug in libuv?

@joyeecheung
Copy link
Member Author

joyeecheung commented May 29, 2018

@addaleax

Is that a bug in libuv?

I thinks so, at least EISDIR does not even make sense for fstat given that the returned result is supposed to tell you if that fd is for a directory or not.

On Windows fstat cannot be called on std fds. In those cases,
we already know that the fd is not for a regular file and can
just use a list of buffers to store the data.

Also makes sure that we don't close fds provided by users
if we cannot call fstat on them.
@joyeecheung
Copy link
Member Author

@jasnell
Copy link
Member

jasnell commented Sep 10, 2018

Ping @joyeecheung

@jasnell jasnell added the stalled Issues and PRs that are stalled. label Sep 10, 2018
@Trott
Copy link
Member

Trott commented Nov 20, 2018

@joyeecheung Still working on this?

@joyeecheung
Copy link
Member Author

@Trott Not really...I'll close this

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. stalled Issues and PRs that are stalled.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Accessing stdin with file descriptor 0 on Windows causes exception if there's no input / if stdin is closed
7 participants