-
Notifications
You must be signed in to change notification settings - Fork 29.9k
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
Migrate process errors from C++ to JS #19973
Conversation
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.
Just had a brief glance at it and it looks very good. I am going to have a closer look at it later on again to give a LG.
This does conflict with at least one other PR at the moment though that I expect to land earlier. Just as a heads up.
src/node.cc
Outdated
if (!args[1]->IsUint32() && !args[1]->IsString()) { | ||
return env->ThrowTypeError("argument 2 must be a number or a string"); | ||
} | ||
CHECK_EQ(args.Length(), 1); |
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.
Should this not be 2?
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.
Right. That means we don't have any test for this function 😱
lib/internal/errors.js
Outdated
@@ -837,6 +837,7 @@ E('ERR_INVALID_SYNC_FORK_INPUT', | |||
TypeError); | |||
E('ERR_INVALID_THIS', 'Value of "this" must be of type %s', TypeError); | |||
E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple', TypeError); | |||
E('ERR_INVALID_UNIX_ID', 'Unix %s id does not exist: %s', Error); |
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.
ERR_INVALID_CREDENTIAL
/ERR_UNKNOWN_CREDENTIAL
? The error message is unambiguous, but it’s not really clear what’s meant by “Unix id” from just seeing the error code, imo
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.
What about ERR_UNKNOWN_IDENTIFIER
?
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.
And changing the message to "Group/User identifier does not exist: %s" ?
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.
@targos I think that might be a bit generic, especially since “unknown identifier” is a term that has a different meaning in a programming language context
I’m fine with changing the error message to what you’re suggesting, but I’m also fine with it the way it is right now :)
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.
ERR_INVALID_CREDENTIAL
sounds better to me since you'd do man credentials
to read the manual on this...or maybe ERR_INVALID_PRIVILEGES
?
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.
Oh, I changed it to ERR_INVALID_CREDENTIAL
but forgot to push. Done now.
lib/internal/process/methods.js
Outdated
validateId(user, 'user'); | ||
validateId(extraGroup, 'extraGroup'); | ||
const result = _initgroups(user, extraGroup); | ||
if (result === 1) { |
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.
This seems rather magical, can you put in a comment around these return values or use some kind of constants shared by both sides?
src/node.cc
Outdated
oct += c - '0'; | ||
} | ||
} | ||
int oct = args[0]->Uint32Value();; |
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.
Can you use the .As<Uint32>()->Value()
cast here instead of the deprecated API?
lib/internal/errors.js
Outdated
@@ -837,6 +837,7 @@ E('ERR_INVALID_SYNC_FORK_INPUT', | |||
TypeError); | |||
E('ERR_INVALID_THIS', 'Value of "this" must be of type %s', TypeError); | |||
E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple', TypeError); | |||
E('ERR_INVALID_UNIX_ID', 'Unix %s id does not exist: %s', Error); |
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.
ERR_INVALID_CREDENTIAL
sounds better to me since you'd do man credentials
to read the manual on this...or maybe ERR_INVALID_PRIVILEGES
?
test/parallel/test-umask.js
Outdated
assert.throws(() => { | ||
process.umask(value); | ||
}, { | ||
code: 'ERR_INVALID_ARG_TYPE', |
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.
This error message reads somewhat odd to me. Shouldn't this be a ERR_INVALID_ARG_VALUE
?
@targos ... this needs a quick rebase if you would. |
be87ffb
to
905e138
Compare
Updated! @joyeecheung I think I addressed all your comments. |
905e138
to
d7bd31d
Compare
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.
LGTM, just a few nits / suggestions.
lib/internal/process/methods.js
Outdated
|
||
function setgroups(groups) { | ||
if (!Array.isArray(groups)) { | ||
throw new ERR_INVALID_ARG_TYPE('groups', 'array', groups); |
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.
It should be Array
lib/internal/process/methods.js
Outdated
function umask(mask) { | ||
if (typeof mask === 'undefined') { | ||
return _umask(mask); | ||
} else if (typeof mask === 'number') { |
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.
Nit: do not use the else
in case it is not required due to the return.
@@ -0,0 +1,58 @@ | |||
'use strict'; | |||
|
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.
I like the consolidation of validation functions!
// 2 ** 31 === 2147483648 | ||
err = new ERR_OUT_OF_RANGE(name, '> -2147483649 && < 2147483648', value); | ||
} | ||
Error.captureStackTrace(err, validateInt32); |
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.
Suggestion: I think it is best to actually keep the internal structure visible in most cases. So I personally would not remove this frame. The same applies to the other validation functions.
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.
I prefer not to change this in this PR.
} else if (!Number.isInteger(value)) { | ||
err = new ERR_OUT_OF_RANGE(name, 'an integer', value); | ||
} else { | ||
const min = positive ? 1 : 0; |
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.
Suggestion: it is not much overhead but the default argument is slower than not having a default in all cases. The check itself could stay as it is, since it already tests for truthy values only.
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.
I removed the default value
err = new ERR_OUT_OF_RANGE(name, 'an integer', value); | ||
} else { | ||
// 2 ** 31 === 2147483648 | ||
err = new ERR_OUT_OF_RANGE(name, '> -2147483649 && < 2147483648', value); |
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.
Just as a note: as far as I know, this function should actually check >= 0 && ...
in all call cases. So we might want to rename the function / add a new one but this does not have to be in this PR.
src/node.cc
Outdated
oct += c - '0'; | ||
} | ||
} | ||
int oct = args[0].As<Uint32>()->Value();; |
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.
Redundant semicolon.
message: /The "directory" argument must be of type string/ | ||
}; | ||
common.expectsError(function() { process.chdir({}); }, err); | ||
common.expectsError(function() { process.chdir(); }, err); |
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.
Please keep the third test but just change it to: process.chdir('x', 'y'); // Should not throw
. That makes sure we have no regression in case the function is changed at any point in time.
Besides that it would also be good to keep assert.throws
as it has a much nicer error output and is otherwise almost identical.
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.
Please keep the third test but just change it to: process.chdir('x', 'y'); // Should not throw. That makes sure we have no regression in case the function is changed at any point in time.
I don't think we need this test. I removed the check because in other functions we never throw when too many arguments are passed.
Besides that it would also be good to keep assert.throws as it has a much nicer error output and is otherwise almost identical.
I know our opinions differ here, but I really like to be able to pass a RegExp. I don't have to put the exact string, so:
- I don't need to make the test fail to know exactly what to put for the message.
- I can use one object validator for multiple test cases (that's what I did here, as error the message is not exactly the same for those cases).
- Message validator is shorter, so less likely to go over 80 chars and also less like to have to be updated in case we change something in the message format.
@@ -43,8 +43,17 @@ assert.strictEqual(old, process.umask()); | |||
|
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.
Would you be so kind and rename this test file to test-process-umask.js
?
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.
done
d7bd31d
to
29f1182
Compare
@nodejs/tsc this needs more TSC reviews, please. |
I'm going to take this off the 10.0.0 milestone. It would need to land today and would need explicit @nodejs/tsc approval (not just no-objections) in order to make it in to 10.0.0 as I'm going to be cutting the release candidate build tomorrow. |
Create a file to centralize argument validators that are used in multiple internal modules. Move validateInt32 and validateUint32 to this file.
Migrate some methods from node.cc to JS in order to properly throw errors with codes.
29f1182
to
6e43560
Compare
Hopefully fixed the Windows errors by defining POSIX-specific methods only if they exist originally on the process object. |
'must be an octal string'); | ||
} | ||
const octal = Number.parseInt(mask, 8); | ||
validateUint32(octal, 'mask'); |
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.
Suggestion: This is actually only testing for <= 2 ** 32
. All other checks are already done due to the RegExp above.
I personally would either remove the extra check or make the whole function stricter to only accept valid entries.
The reason validateUint32
is used for numbers is only about making sure no negative numbers got passed in (as far as I know).
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.
Do you know what is the largest allowed value?
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.
@targos In some fs methods we throw if the mode is larger than 0o777
. It is not strictly documented wether we mask off or throw if the mode_t
type of value passed to any API is larger than that though.
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.
What happens in the system if the value is larger than 0o777
?
For example if you pass 0o12345
? is it truncated to 0o345
?
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.
Suggestion: add a TODO to investigate and land the PR. In fs
there are a couple of validations that need improvements, especially having more consistent checks. I am also working on some of those.
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.
@targos Yes it gets truncated/masked. http://man7.org/linux/man-pages/man2/umask.2.html
umask() sets the calling process's file mode creation mask (umask) to
mask & 0777 (i.e., only the file permission bits of mask are used),
and returns the previous value of the mask.
Create a file to centralize argument validators that are used in multiple internal modules. Move validateInt32 and validateUint32 to this file. PR-URL: nodejs#19973 Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: James M Snell <[email protected]>
Migrate some methods from node.cc to JS in order to properly throw errors with codes. PR-URL: nodejs#19973 Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: James M Snell <[email protected]>
To ease future backports, create the process/methods file introduced in nodejs#19973. This commit just adds the JS functions that forward calls to C++ and does not change type checking.
To ease future backports, create the process/methods file introduced in #19973. This commit just adds the JS functions that forward calls to C++ and does not change type checking. PR-URL: #21172 Reviewed-By: Joyee Cheung <[email protected]>
To ease future backports, create the process/methods file introduced in #19973. This commit just adds the JS functions that forward calls to C++ and does not change type checking. PR-URL: #21172 Reviewed-By: Joyee Cheung <[email protected]>
commit 2b3b84822baa258fe67f17979b17fac523455612
commit aeb33c9b0d4be6693d7eda0810b4c3f4d213d743
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes