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: fix handling of struct stat fields #8515

Closed
wants to merge 2 commits into from

Conversation

addaleax
Copy link
Member

@addaleax addaleax commented Sep 13, 2016

Checklist
  • make -j4 test (UNIX), or vcbuild test nosign (Windows) passes
  • tests and/or benchmarks are included (how? I’m open to suggestions.)
  • commit message follows commit guidelines
Affected core subsystem(s)

fs

Description of change

FChown and Chown test that the uid and gid parameters they receive are unsigned integers, but Stat() and FStat() would return the corresponding fields of struct stat as signed integers. Applications which pass those these values directly to Chown may fail
(e.g. for nobody on OS X, who has an uid of -2, see e.g. nodejs/node-v0.x-archive#5890).

This patch changes the Integer::New() call for uid and gid to Integer::NewFromUnsigned().

All other fields are kept as they are, for performance, but strictly speaking the respective sizes of those fields aren’t specified, either.

Ref: npm/npm#13918

/cc @nodejs/fs

CI: https://ci.nodejs.org/job/node-test-commit/5026/

@nodejs-github-bot nodejs-github-bot added the c++ Issues and PRs that require attention from people who are familiar with C++. label Sep 13, 2016
@addaleax addaleax added fs Issues and PRs related to the fs subsystem / file system. lts-watch-v4.x labels Sep 13, 2016
#define X(name) \
Local<Value> name = Integer::NewFromUnsigned(env->isolate(), s->st_##name); \
if (name.IsEmpty()) \
return handle_scope.Escape(Local<Object>()); \
Copy link
Member

Choose a reason for hiding this comment

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

Escaping an empty handle isn't necessary. I realize this is copied from existing code, though.

Copy link
Member Author

Choose a reason for hiding this comment

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

I’ll remove that in all locations here, then

@bnoordhuis
Copy link
Member

LGTM. Technically, it's uv_stat_t, not struct stat.

`FChown` and `Chown` test that the `uid` and `gid` parameters
they receive are unsigned integers, but `Stat()` and `FStat()`
would return the corresponding fields of `uv_stat_t` as signed
integers. Applications which pass those these values directly
to `Chown` may fail
(e.g. for `nobody` on OS X, who has an `uid` of `-2`, see e.g.
nodejs/node-v0.x-archive#5890).

This patch changes the `Integer::New()` call for `uid` and `gid`
to `Integer::NewFromUnsigned()`.

All other fields are kept as they are, for performance, but
strictly speaking the respective sizes of those
fields aren’t specified, either.

Ref: npm/npm#13918
@addaleax
Copy link
Member Author

Updated with uv_stat_t in the commit message and escaping the empty handles removed

@bnoordhuis
Copy link
Member

LGTM

# if defined(__POSIX__)
X(blksize)
# else
Local<Value> blksize = Undefined(env->isolate());
# endif
#undef X

// Integers.
#define X(name) \
Local<Value> name = Integer::NewFromUnsigned(env->isolate(), s->st_##name); \
Copy link
Contributor

Choose a reason for hiding this comment

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

This must be Integer::New, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

… yeah, sorry.

@addaleax
Copy link
Member Author

@thefourtheye updated! :)

@thefourtheye
Copy link
Contributor

I am not sure, if I am looking in the right place. But if I am following the definition here, correctly, even dev, mode, nlink, and rdev are also unsigned it seems.

@addaleax
Copy link
Member Author

@thefourtheye Yeah, that doesn’t look like the right place… usually, you’d want to take a peek at the public headers which define struct stat, but as Ben noted, libuv ships its own type for that. Either way, the result might be system-dependent, POSIX doesn’t seem to specify anything about size or signedness of the fields.

That being said… yes, I’ve looked into it, and it seems the fields you mentioned are unsigned on Linux, too. Worse, dev, ino, nlink and rdev are 64 bit wide on my system, so using Integer::New(FromUnsigned) isn’t really appropriate… calling Number::New may be more correct, but it does seem to come with a slight but noticeable performance impact due to the extra range checking it does (about -1 % for me).

@bnoordhuis
Copy link
Member

Worse, dev, ino, nlink and rdev are 64 bit wide on my system, so using Integer::New(FromUnsigned) isn’t really appropriate… calling Number::New may be more correct

Pragmatically though, those are going to fit in a uint32_t for the foreseeable future (maybe, just maybe, with the exception of ino.)

@thefourtheye
Copy link
Contributor

So, we are going to leave them as signed for the time being?

@addaleax
Copy link
Member Author

So, we are going to leave them as signed for the time being?

I’d be okay with that, if only for the fear of unnecessarily breaking things… alternatively, I can update this PR with something that auto-detects signedness of the fields?

@thefourtheye
Copy link
Contributor

@addaleax Nah, we can keep it, simple, as it is. LGTM. I wonder how our CITGM never got this.

@addaleax
Copy link
Member Author

I wonder how our CITGM never got this.

I think one of the reasons is that it leaves quite a lot of code intact, it just blows up when you try to pass the uid/git to chown or fchown… but that’s not something you can’t usually do without root. As long as I’m not missing anything, doing an actual, working chown is basically untested by Node. :/

Copy link
Member

@jasnell jasnell left a comment

Choose a reason for hiding this comment

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

LGTM but I wonder if there's a regression test that could be added for this.

@addaleax
Copy link
Member Author

@jasnell Maybe I could get a cctest for this together… I’ll look into that as soon as I have the time, but I kind of don’t want to block this PR on that because this PR itself would be a blocker for updating to [email protected] in deps/.

@addaleax
Copy link
Member Author

@addaleax
Copy link
Member Author

Landed in c5545f2

@addaleax addaleax closed this Sep 19, 2016
@addaleax addaleax deleted the stat-unsigned branch September 19, 2016 12:59
addaleax added a commit that referenced this pull request Sep 19, 2016
`FChown` and `Chown` test that the `uid` and `gid` parameters
they receive are unsigned integers, but `Stat()` and `FStat()`
would return the corresponding fields of `uv_stat_t` as signed
integers. Applications which pass those these values directly
to `Chown` may fail
(e.g. for `nobody` on OS X, who has an `uid` of `-2`, see e.g.
nodejs/node-v0.x-archive#5890).

This patch changes the `Integer::New()` call for `uid` and `gid`
to `Integer::NewFromUnsigned()`.

All other fields are kept as they are, for performance, but
strictly speaking the respective sizes of those
fields aren’t specified, either.

Ref: npm/npm#13918
PR-URL: #8515
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Sakthipriyan Vairamani <[email protected]>
Reviewed-By: James M Snell <[email protected]>

undo accidental change to other fields of uv_fs_stat
addaleax added a commit to addaleax/node-graceful-fs that referenced this pull request Sep 23, 2016
At the time of writing, all currently published versions of Node.js
return signed 32-bit integers in their return values for the `uid`
and `gid` fields of `fs.Stats` instances.

This is problematic, because some of Node’s other `fs` methods like
`chown` expect unsigned 32-bit integer input and throw when encountering
negative integers; this has broken e.g. `sudo npm install -g` on `OS X`,
where `nobody` has a UID that would be returned as `-2` by `fs.stat()`.

Ref: nodejs/node#8515
Ref: npm/npm#13918
Fishrock123 pushed a commit that referenced this pull request Oct 11, 2016
`FChown` and `Chown` test that the `uid` and `gid` parameters
they receive are unsigned integers, but `Stat()` and `FStat()`
would return the corresponding fields of `uv_stat_t` as signed
integers. Applications which pass those these values directly
to `Chown` may fail
(e.g. for `nobody` on OS X, who has an `uid` of `-2`, see e.g.
nodejs/node-v0.x-archive#5890).

This patch changes the `Integer::New()` call for `uid` and `gid`
to `Integer::NewFromUnsigned()`.

All other fields are kept as they are, for performance, but
strictly speaking the respective sizes of those
fields aren’t specified, either.

Ref: npm/npm#13918
PR-URL: #8515
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Sakthipriyan Vairamani <[email protected]>
Reviewed-By: James M Snell <[email protected]>

undo accidental change to other fields of uv_fs_stat
@MylesBorins
Copy link
Contributor

@addaleax should this be backported?

@addaleax
Copy link
Member Author

@thealphanerd This seems to land cleanly on v4.x-staging with tests passing, and it makes sense to have this on LTS for me.

MylesBorins pushed a commit that referenced this pull request Oct 24, 2016
`FChown` and `Chown` test that the `uid` and `gid` parameters
they receive are unsigned integers, but `Stat()` and `FStat()`
would return the corresponding fields of `uv_stat_t` as signed
integers. Applications which pass those these values directly
to `Chown` may fail
(e.g. for `nobody` on OS X, who has an `uid` of `-2`, see e.g.
nodejs/node-v0.x-archive#5890).

This patch changes the `Integer::New()` call for `uid` and `gid`
to `Integer::NewFromUnsigned()`.

All other fields are kept as they are, for performance, but
strictly speaking the respective sizes of those
fields aren’t specified, either.

Ref: npm/npm#13918
PR-URL: #8515
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Sakthipriyan Vairamani <[email protected]>
Reviewed-By: James M Snell <[email protected]>

undo accidental change to other fields of uv_fs_stat
MylesBorins pushed a commit that referenced this pull request Oct 26, 2016
`FChown` and `Chown` test that the `uid` and `gid` parameters
they receive are unsigned integers, but `Stat()` and `FStat()`
would return the corresponding fields of `uv_stat_t` as signed
integers. Applications which pass those these values directly
to `Chown` may fail
(e.g. for `nobody` on OS X, who has an `uid` of `-2`, see e.g.
nodejs/node-v0.x-archive#5890).

This patch changes the `Integer::New()` call for `uid` and `gid`
to `Integer::NewFromUnsigned()`.

All other fields are kept as they are, for performance, but
strictly speaking the respective sizes of those
fields aren’t specified, either.

Ref: npm/npm#13918
PR-URL: #8515
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Sakthipriyan Vairamani <[email protected]>
Reviewed-By: James M Snell <[email protected]>

undo accidental change to other fields of uv_fs_stat
@MylesBorins MylesBorins mentioned this pull request Oct 26, 2016
@JLHwung JLHwung mentioned this pull request Nov 3, 2017
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. fs Issues and PRs related to the fs subsystem / file system.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants