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

lib: fix realpathSync resolving to invalid path (#54200) #54458

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
8 changes: 8 additions & 0 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2731,6 +2731,14 @@ function realpathSync(p, options) {
}
resolvedLink = pathModule.resolve(previous, linkTarget);

// If resolvedLink is not valid, or is a pipe/socket, stop resolving and break out of the loop
// Ref: https://github.com/nodejs/node/issues/54200
const resolvedLinkStats = binding.lstat(resolvedLink, false, undefined, false /* throwIfNoEntry */);
if (!resolvedLinkStats || isFileType(resolvedLinkStats, S_IFIFO) ||
isFileType(resolvedLinkStats, S_IFSOCK)) {
break;
}

cache?.set(base, resolvedLink);
if (!isWindows) seenLinks.set(id, linkTarget);
}
Expand Down
54 changes: 54 additions & 0 deletions test/parallel/test-linux-dev-stdin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use strict';
const common = require('../common');
const tmpdir = require('../common/tmpdir');
const fs = require('fs');

//
// This test ensures Node.js doesn't crash when reading from /dev/stdin as an input.
// Ref: https://github.com/nodejs/node/issues/54200
//

if (!fs.existsSync('/dev/stdin')) {
common.skip('Only test on platforms having /dev/stdin');
}

const child_process = require('child_process');
const assert = require('assert');
const { describe, it } = require('node:test');
const { join } = require('path');

describe("Test reading SourceCode from stdin and it's symlinks", () => {
it('Test reading sourcecode from /dev/stdin', () => {
const cp = child_process.execSync(
`printf 'console.log(1)' | "${process.execPath}" /dev/stdin`,
{ stdio: 'pipe' }
);
assert.strictEqual(cp.toString(), '1\n');
});

it('Test reading sourcecode from a symlink to /dev/stdin', () => {
tmpdir.refresh();
const tmp = tmpdir.resolve('./stdin');
fs.symlinkSync('/dev/stdin', tmp);
const cp2 = child_process.execSync(
`printf 'console.log(2)' | "${process.execPath}" ${tmp}`,
{ stdio: 'pipe' }
);
assert.strictEqual(cp2.toString(), '2\n');
});

it('Test reading sourcecode from a symlink to the `readlink -f /dev/stdin`', () => {
const devStdin = fs.readlinkSync('/dev/stdin');
let devStdinRealPath = devStdin;
if (common.isMacOS) {
// macOS `readlink` gives back the relative path, so we need to convert it to absolute path.
devStdinRealPath = join('/dev', devStdin);
}

const cp3 = child_process.execSync(
`printf 'console.log(3)' | "${process.execPath}" "${devStdinRealPath}"`,
{ stdio: 'pipe' }
);
assert.strictEqual(cp3.toString(), '3\n');
});
});
Loading