Repository navigation
No error was thrown when spawn command was existed but non-executable #26852
Description
Activity
- addedchild_processIssues and PRs related to the child_process subsystem.Issues and PRs related to the child_process subsystem.
on Mar 22, 2019 IMO going from a throw to an emitted error is a good thing, since
spawnis supposed to be async.Let me show what I think is a real bug in Node.js.
With this script located in
/tmp/child_process, and an empty, non-executable file/tmp/child_process/y:'use strict'; const { spawn } = require('child_process'); const { existsSync } = require('fs'); const { resolve } = require('path'); function test(path) { const exists = existsSync(path); const child = spawn(path); const hasStdin = !!child.stdin; child.on('error', (e) => { console.log(`Path: "${path}".\nExists: ${exists}.\nHas stdin: ${hasStdin}\n\n`); }); } test('x'); test('/tmp/child_process/x'); test('./x'); test('y'); test('/tmp/child_process/y'); test('./y');
Path: "x". Exists: false. Has stdin: true Path: "/tmp/child_process/x". Exists: false. Has stdin: true Path: "./x". Exists: false. Has stdin: true Path: "y". Exists: true. Has stdin: true Path: "/tmp/child_process/y". Exists: true. Has stdin: false Path: "./y". Exists: true. Has stdin: falseWe have a clear inconsistency. If the file does not exist, the object returned by
spawnalways has thestdinproperty. If the file exists but is not executable,stdinis only present if the path doesn't start with./or/./cc @nodejs/child_process
Reacted by ehmicky, Elliott Marquez and Sindre Sorhus@bnoordhuis What do you think?
So, why did Node 10+ change spawn behaviors? On purpose or regressions?
The behavior change comes from #19294, which began classifying
EACCESas a runtime error (emitting vs. throwing).If the file exists but is not executable, stdin is only present if the path doesn't start with ./ or /
I think this is more about the error that's occurring. The two cases where "has stdin" is
falseare bothEACCES, while the rest areENOENT.ENOENTgets special treatment here. Since that comment was originally written, we've started handlingUV_EAGAINandUV_EACCEStoo, but they should be treated the same asUV_ENOENTin my opinion.We can:
- Remove the special handling of
UV_ENOENT, and return all runtime errors. This is definitely a breaking change, as it makes one test fail. I prefer this option because that comment acknowledges its own silliness, and it's kind of wasteful to set up stdio for no reason. I'm willing to PR this change. - Include
UV_EACCESandUV_EAGAINin the special handling withUV_ENOENT. I didn't test this variation. It's also a breaking change, even if our test suite doesn't catch it. - Do something else, including nothing.
- Remove the special handling of
Actually, on second thought, we probably do want to setup stdio to prevent situations like nodejs/help#1769.
Reacted by Gireesh Punathilhaving
stdiosetup in all runtime error scenarios (though am unable to figure out what needs to be done in the code to meet this) looks to be the right way forward for me. That way, from programmer's perspective, they could meaningfully tap bothstdioanderrorstreams of the child without breaking the program.- added a commit that references this issue
on May 20, 2019 - added a commit that references this issue
on May 21, 2019
10.2.0/11.12.0
Darwin localhost 16.7.0 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 x86_64
Suppose we have following test script and file
notexeexist in the same folder. Butnotexehas no executable permission.So, why did Node 10+ change spawn behaviors? On purpose or regressions?