diff --git a/lib/fs.js b/lib/fs.js index ad90551f40f1..50bea658163c 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -614,7 +614,11 @@ function readFileSync(path, options) { if ((options.encoding === 'utf8' || options.encoding === 'utf-8') && !hasUserBuffer) { - if (!isInt32(path)) { + if (isInt32(path)) { + // V8 does not report -0 as an int32, so it would reach the binding as a + // path instead of a file descriptor. + path |= 0; + } else { path = getValidatedPath(path); } return binding.readFileUtf8(path, stringToFlags(options.flag)); @@ -2995,7 +2999,11 @@ function writeFileSync(path, data, options) { // C++ fast path for string data and UTF8 encoding if (typeof data === 'string' && (options.encoding === 'utf8' || options.encoding === 'utf-8')) { - if (!isInt32(path)) { + if (isInt32(path)) { + // V8 does not report -0 as an int32, so it would reach the binding as a + // path instead of a file descriptor. + path |= 0; + } else { path = getValidatedPath(path); } diff --git a/test/parallel/test-fs-negative-zero.js b/test/parallel/test-fs-negative-zero.js index 538cea67faaa..09f965eb171f 100644 --- a/test/parallel/test-fs-negative-zero.js +++ b/test/parallel/test-fs-negative-zero.js @@ -2,6 +2,8 @@ require('../common'); +const assert = require('assert'); +const { spawnSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const os = require('os'); @@ -29,5 +31,18 @@ ignoreExpectedError(() => fs.mkdirSync(missing, { mode: -0 })); ignoreExpectedError(() => fs.chmodSync(missing, -0)); ignoreExpectedError(() => fs.writeFileSync(missing, '', { mode: -0 })); +// -0 is accepted as file descriptor 0. Writing an empty string reaches the +// utf8 fast path without issuing a write on the descriptor. +fs.writeFileSync(-0, ''); +fs.appendFileSync(-0, ''); + +const child = spawnSync( + process.execPath, + ['-e', 'process.stdout.write(require("fs").readFileSync(-0, "utf8"))'], + { input: 'hello' }, +); +assert.strictEqual(child.status, 0); +assert.strictEqual(child.stdout.toString(), 'hello'); + fs.watchFile(missing, { interval: -0 }, () => {}); fs.unwatchFile(missing);