Closed
Description
- Version: 12.6.0
- Platform:
64-bit (Windows 10 Education version 1809)
,Linux lenovo520 4.15.0-70-generic #79-Ubuntu SMP Tue Nov 12 10:36:11 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
- Subsystem:
fs
,stream
What steps will reproduce the bug?
Run this code with node
const fs = require("fs");
const { spawnSync } = require("child_process");
const pipeline = require("util").promisify(require("stream").pipeline);
async function main() {
const src = fs.createReadStream("src.exe");
const dest = fs.createWriteStream("dest.exe", { mode: 0o755 });
await pipeline(src, dest);
dest.destroy();
console.dir(spawnSync("dest.exe", ["--version"]));
}
main().finally(() => console.log("DONE"));
How often does it reproduce? Is there a required condition?
It doesn't reproduce on all platforms stably. On my laptop it does always reproduce on Windows 10. I am not sure what is the required condition for this...
What is the expected behavior?
As per documentation of .destroy()
:
This is a destructive and immediate way to destroy a stream
I expect write-stream to release the file handle during the call to .destroy()
, so that the next call to spawnSync
of the copied file does execute the binary successfully.
What do you see instead?
Windows 10 x64
D:\junk\catch>node index.js
{
error: Error: spawnSync dest.exe EBUSY
at Object.spawnSync (internal/child_process.js:1041:20)
at spawnSync (child_process.js:609:24)
at main (D:\junk\catch\index.js:12:17)
at processTicksAndRejections (internal/process/task_queues.js:85:5) {
errno: 'EBUSY',
code: 'EBUSY',
syscall: 'spawnSync dest.exe',
path: 'dest.exe',
spawnargs: [ '--version' ]
},
status: null,
signal: null,
output: null,
pid: 0,
stdout: null,
stderr: null
}
DONE
D:\junk\catch>
Ubuntu 18.04.3
~/my/junk/stream $ node index.js
{
error: Error: spawnSync ./dest.exe EACCES
at Object.spawnSync (internal/child_process.js:1045:20)
at spawnSync (child_process.js:597:24)
at main (/home/veetaha/my/junk/stream/index.js:12:17)
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
errno: -13,
code: 'EACCES',
syscall: 'spawnSync ./dest.exe',
path: './dest.exe',
spawnargs: [ '--version' ]
},
status: null,
signal: null,
output: null,
pid: 6261,
stdout: null,
stderr: null
}
DONE
~/my/junk/stream $
Additional information
The original problem was when downloading a binary executable from GitHub releases for rust-analyzer
. You can see the initial discussion on the bug here.
The workaround for this that we use now is to wait for "close"
event on writable-stream after the call to .destroy()
, i.e.
await stream.pipeline(src, dest);
return new Promise(resolve => {
dest.on("close", resolve);
dest.destroy();
});