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

child_process: ignore undef/proto values of env #15089

Closed
wants to merge 2 commits into from

Conversation

Gerhut
Copy link
Contributor

@Gerhut Gerhut commented Aug 30, 2017

At present, undefined values of env option will be transferred as an "undefined" string value and values in the prototype will also be included, which are not usual behaviors.

Since non-string env values & prototype values are undocumented, this change may be treated as a bugfix or a breaking change.

Tested on Mac, Windows not yet.

Fixes: #15087

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

child_process

@nodejs-github-bot nodejs-github-bot added the child_process Issues and PRs related to the child_process subsystem. label Aug 30, 2017
@@ -467,7 +467,10 @@ function normalizeSpawnArguments(file, args, options) {
var envPairs = [];

for (var key in env) {
Copy link
Member

@benjamingr benjamingr Aug 30, 2017

Choose a reason for hiding this comment

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

I think this should optimally be:

const envPairs = Object.keys(env).filter(Boolean).map(key => `${key}=${env[key]}`)

or something similar (ignore empty keys in addition to undefined ones.

I do think it's underspecified though. So I'll wait for someone who understands it better to weigh in.

Copy link
Contributor

Choose a reason for hiding this comment

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

OMG .filter(Boolean) 💘
I used to do .filter((x) => x), but have alway looked for a built-in.

P.S. @Gerhut in TF&I (node 8.3.0 and newer) for ... of loop are almost 10 time faster than for ... in loops, and it's supports Object.entries()

Copy link
Member

Choose a reason for hiding this comment

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

@refack but the call to Object.keys is itself about as slow as doing for... in - in this particular case I don't think performance is important given the time it takes to create a process and all 😅

Copy link
Contributor

Choose a reason for hiding this comment

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

@benjamingr agreed.
I'm just promoting TF&I good behaviour (no more CranksharfScript)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since the code around still in legacy Syntax, should I be allowed to use modern syntax? If so I will modify them in modern syntax.

Copy link
Member

Choose a reason for hiding this comment

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

@Gerhut yes, in general new code should be written in new syntax.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

However, for..in includes keys in prototype, and keys-in-prototype of env test exists at https://github.com/nodejs/node/blob/master/test/parallel/test-child-process-env.js#L31-L33 . Changing to Object.keys/entries will fail them

Copy link
Member

Choose a reason for hiding this comment

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

I think it would be good to remove that test case and only use Object.keys. There is not much reasoning in the original commit about why it was added but I think this is actually a faulty behavior.

Copy link
Member

Choose a reason for hiding this comment

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

Using filter(Boolean) would be a bad decision to use though as it would remove a empty string and any other falsy value as well.

@benjamingr
Copy link
Member

Tagging as semver-major preemptively since this is a user facing behavioral change in an API marked 2 - Stable.

I don't feel strongly about it - I just don't want it to be missed.

@benjamingr benjamingr added the semver-major PRs that contain breaking changes and should be released in the next major version. label Aug 30, 2017
@benjamingr
Copy link
Member

@Gerhut thank you for the contribution. Just to explain the process at this point:

  • Collaborators are going to look at this pull request for around 48 hours to discuss the change.
  • People will comment on the actual code and might suggest changes.
  • People will comment on the merit of the actual changes and evaluate how they impact the ecosystem.

If at any point you would like assistance with the pull request or have any question about the process feel free to ask here. Welcome.

Copy link
Contributor

@cjihrig cjihrig left a comment

Choose a reason for hiding this comment

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

Can you add documentation notes and function level changelog entries for this.

@addaleax
Copy link
Member

LGTM as semver-major

@BridgeAR
Copy link
Member

BridgeAR commented Aug 31, 2017

I personally am not convinced about this. Why should undefined and null be treated otherwise than any other primitive besides strings? They will all be coerced to a string and I can actually imagine that some people might explicitly pass undefined or null as env value. Having a implicit removal is not what I would call intuitive.
I would rather have a error thrown as a user to know what is happening and that it is better to always pass in values as string.

@jasnell
Copy link
Member

jasnell commented Sep 1, 2017

I'm kind of half-way where @BridgeAR is. I would say null should be ToString'd and undefined should be ignored/omitted.

@targos
Copy link
Member

targos commented Sep 1, 2017

I think it makes sense to ignore undefined too. No opinion on null.

@addaleax
Copy link
Member

addaleax commented Sep 2, 2017

100 % totally official twitter poll: https://twitter.com/addaleax/status/903796395865452544

@BridgeAR
Copy link
Member

BridgeAR commented Sep 3, 2017

Looks like the poll says null should be stringified and undefined should be removed. @Gerhut would you be so kind and update the PR accordingly?

I personally still think we should not remove it but throw an error instead and the poll did not cover that part but it seems like most people agree on removing it, so I will not hold this off.

@refack
Copy link
Contributor

refack commented Sep 3, 2017

BTW: need to think about how to make this consistent with assignment (maybe in a future PR)

node/doc/api/process.md

Lines 827 to 842 in 98d8db3

Assigning a property on `process.env` will implicitly convert the value
to a string.
Example:
```js
process.env.test = null;
console.log(process.env.test);
// => 'null'
process.env.test = undefined;
console.log(process.env.test);
// => 'undefined'
```
Use `delete` to delete a property from `process.env`.

@Gerhut
Copy link
Contributor Author

Gerhut commented Sep 4, 2017

PR Updated.

Moreover, Would "ignore keys in prototype of env option" be another breaking change of bugfix? (See outdated review comment)

I just feel this change should be in another PR to discuss separately. There could be an use case that using process.env as a base environment variables and extend it in env option. It might using prototyping (env = Object.create(process.env); env.FOO='BAR'; spawn(exe, {env};).

BridgeAR
BridgeAR previously approved these changes Sep 11, 2017
Copy link
Member

@BridgeAR BridgeAR left a comment

Choose a reason for hiding this comment

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

In general LGTM but I would like my comment to be addressed.

@@ -466,8 +466,10 @@ function normalizeSpawnArguments(file, args, options) {
var env = options.env || process.env;
var envPairs = [];

for (var key in env) {
envPairs.push(key + '=' + env[key]);
for (const [key, value] of Object.entries(env)) {
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure how fast Object.entries is and I somewhat expect it to be slower than e.g. using Object.keys or using for ... in with a Object.hasOwnProperty.call(env, key) check. The latter will definitely be faster in upcoming v8 versions but probably not right now.

@BridgeAR
Copy link
Member

@Gerhut I think it is fine to keep it in this PR but it would be just as fine to move it to another one!

If this is kept in the PR the commit message has to be updated though. This has to be done one way or the other anyway though since it currently has information that is not necessary for landing. So I think it is your call. If you want to land another commit - feel free to open a second PR for that.

@bnoordhuis
Copy link
Member

I'm -0. process.env and the .env option currently behave the same: values are tostring-ed. This PR introduces a discrepancy for no good reason I can see.

@Gerhut Gerhut changed the title child_process: ignore null/undefined values of env child_process: ignore undef/proto values of env Sep 12, 2017
@BridgeAR BridgeAR dismissed their stale review September 19, 2017 20:51

Dimissed my ok as I am also -0 on the change but I do not want to block it either.

@BridgeAR
Copy link
Member

This is semver major and needs some LGs @nodejs/tsc

It is still a tiny bit controversial in general though, so please read all the comments as well.

@evanlucas
Copy link
Contributor

I'm on the fence on this one. Deviating from how null and undefined are handled in process.env makes this more confusing to me...

@targos
Copy link
Member

targos commented Sep 25, 2017

I would be in favour of the same change for process.env

'HELLO': 'WORLD'
'HELLO': 'WORLD',
'UNDEFINED': undefined,
'NULL': null
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add 'EMPTY': ''

@@ -412,7 +412,8 @@ Use `cwd` to specify the working directory from which the process is spawned.
If not given, the default is to inherit the current working directory.

Use `env` to specify environment variables that will be visible to the new
process, the default is [`process.env`][].
process, the default is [`process.env`][], `undefined` values in `env` will be
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion keep the old line, and add a new sentence:

process, the default is [`process.env`][].
`undefined` values in `env` will be ignored.

@BridgeAR BridgeAR requested a review from a team December 6, 2017 03:33
for (var key in env) {
envPairs.push(`${key}=${env[key]}`);
for (const key of Object.keys(env)) {
const value = env[key]
Copy link
Member

Choose a reason for hiding this comment

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

Can you make sure running make lint passes?

At present, undefined values of env option will be transferred as
a "undefined" string value, and values in prototype will also be
included, which are not usual behaviors.

Since non-string env values & prototype values are undocumented,
this change may be treated as a bugfix or a breaking change.

Tested on Mac, Windows not yet.

Fixes: nodejs#15087
@Gerhut
Copy link
Contributor Author

Gerhut commented Dec 6, 2017

Sorry for only ran make test-parallel these times.

@targos
Copy link
Member

targos commented Jan 15, 2018

@targos
Copy link
Member

targos commented Jan 15, 2018

Pushed a fix for Windows.
CI: https://ci.nodejs.org/job/node-test-commit-windows-fanned/14890/

targos pushed a commit to targos/node that referenced this pull request Jan 15, 2018
At present, undefined values of env option will be transferred as
a "undefined" string value, and values in prototype will also be
included, which are not usual behaviors.

This commit prevents those to be transferred to the environment of
the child process.

PR-URL: nodejs#15089
Fixes: nodejs#15087
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
@targos
Copy link
Member

targos commented Jan 15, 2018

Landed in 85739b6.
Thank you @Gerhut for your patience and first contribution to Node!

@MylesBorins
Copy link
Contributor

MylesBorins commented Jan 17, 2018

In future please run CITGM before landing semver major commits

edit: for context this broke CITGM

@targos
Copy link
Member

targos commented Jan 17, 2018

Sorry about that

@apapirovski
Copy link
Member

I'll just leave a note here to anyone landing this in the future, it can't land without #18210.

targos added a commit to targos/node that referenced this pull request Jan 23, 2018
Before this commit, setting a property of process.env to undefined
would set the value to the string "undefined". This changes the
behavior to instead remove the value, working like the delete operator.

Refs: nodejs#15089
TimothyGu added a commit that referenced this pull request Mar 7, 2018
PR-URL: #18990
Refs: #15089
Refs: #18158
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
MayaLekova pushed a commit to MayaLekova/node that referenced this pull request May 8, 2018
PR-URL: nodejs#18990
Refs: nodejs#15089
Refs: nodejs#18158
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
child_process Issues and PRs related to the child_process subsystem. semver-major PRs that contain breaking changes and should be released in the next major version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Should spawn with undefined env value be treated as "undefined" string?