-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
Infinite event loop after calling fs.realpath on 16-inch Macbook #33936
Comments
Oh dear, that looks like another instance of node using doubles to represent inode numbers, and losing precision in the process. It should be easy to fix by switching over to bigints: diff --git a/lib/fs.js b/lib/fs.js
index 8d2a1e044e..5319b2d375 100644
--- a/lib/fs.js
+++ b/lib/fs.js
@@ -1608,7 +1608,7 @@ function realpathSync(p, options) {
// On windows, check that the root exists. On unix there is no need.
if (isWindows && !knownHard[base]) {
const ctx = { path: base };
- binding.lstat(pathModule.toNamespacedPath(base), false, undefined, ctx);
+ binding.lstat(pathModule.toNamespacedPath(base), true, undefined, ctx);
handleErrorFromBinding(ctx);
knownHard[base] = true;
}
@@ -1650,7 +1650,7 @@ function realpathSync(p, options) {
const baseLong = pathModule.toNamespacedPath(base);
const ctx = { path: base };
- const stats = binding.lstat(baseLong, false, undefined, ctx);
+ const stats = binding.lstat(baseLong, true, undefined, ctx);
handleErrorFromBinding(ctx);
if (!isFileType(stats, S_IFLNK)) {
@@ -1673,7 +1673,7 @@ function realpathSync(p, options) {
}
if (linkTarget === null) {
const ctx = { path: base };
- binding.stat(baseLong, false, undefined, ctx);
+ binding.stat(baseLong, true, undefined, ctx);
handleErrorFromBinding(ctx);
linkTarget = binding.readlink(baseLong, undefined, undefined, ctx);
handleErrorFromBinding(ctx);
@@ -1694,7 +1694,7 @@ function realpathSync(p, options) {
// On windows, check that the root exists. On unix there is no need.
if (isWindows && !knownHard[base]) {
const ctx = { path: base };
- binding.lstat(pathModule.toNamespacedPath(base), false, undefined, ctx);
+ binding.lstat(pathModule.toNamespacedPath(base), true, undefined, ctx);
handleErrorFromBinding(ctx);
knownHard[base] = true;
} (note: that's for That inode number, 1152921500312396900, is well beyond the range of numbers that a 64 bits floating point number can accurately represent (which ends at 2**53.) Am I right that |
The `fs.realpath` / `fs.realpathSync` cache already seen symbolic links using the inode number which may be longer that max supported JS number (2**53) and will therefore be incorrectly handled by possibly entering infinite loop of calling stat on the same node. This PR changes those functions (where appropriate) to use bigint for inode numbers. Fixes: nodejs#33936
The `fs.realpath` / `fs.realpathSync` cache already seen symbolic links using the inode number which may be longer that max supported JS number (2**53) and will therefore be incorrectly handled by possibly entering infinite loop of calling stat on the same node. This PR changes those functions (where appropriate) to use bigint for inode numbers. Fixes: #33936 PR-URL: #33945 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
The `fs.realpath` / `fs.realpathSync` cache already seen symbolic links using the inode number which may be longer that max supported JS number (2**53) and will therefore be incorrectly handled by possibly entering infinite loop of calling stat on the same node. This PR changes those functions (where appropriate) to use bigint for inode numbers. Fixes: #33936 PR-URL: #33945 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
The `fs.realpath` / `fs.realpathSync` cache already seen symbolic links using the inode number which may be longer that max supported JS number (2**53) and will therefore be incorrectly handled by possibly entering infinite loop of calling stat on the same node. This PR changes those functions (where appropriate) to use bigint for inode numbers. Fixes: #33936 PR-URL: #33945 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
The `fs.realpath` / `fs.realpathSync` cache already seen symbolic links using the inode number which may be longer that max supported JS number (2**53) and will therefore be incorrectly handled by possibly entering infinite loop of calling stat on the same node. This PR changes those functions (where appropriate) to use bigint for inode numbers. Fixes: #33936 PR-URL: #33945 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
The `fs.realpath` / `fs.realpathSync` cache already seen symbolic links using the inode number which may be longer that max supported JS number (2**53) and will therefore be incorrectly handled by possibly entering infinite loop of calling stat on the same node. This PR changes those functions (where appropriate) to use bigint for inode numbers. Fixes: #33936 PR-URL: #33945 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net>
10, 12 and Latest
MacOS 10.15.5 (16-inch, 2019)
What steps will reproduce the bug?
just call
fs.realpath
with/usr/bin/tclsh
as first parameter.Callback will not be executed, and the node process will be in an infinite event loop. (Not dead, but having high cpu usage).
How often does it reproduce? Is there a required condition?
Every time.
What is the expected behavior?
Callback should be executed as expected.
Additional information
Little inspecting into this issue:
The link path for /usr/bin/tclsh:
In the fs.js, the realpath function attempts to use
seenLinks
to store symbolicLinks that have been already visited.However, on MacOS 10.15.5, 16-inch MacOS, calling node's
fs.lstat
on/usr/bin/tclsh
andusr/bin/tclsh8.5
share the same dev and ino number. This means that the seenLinks for id ofusr/bin/tclsh8.5
will target to itself, then the infinite loop happens.Another interesting thing, it looks like the
fs.lstat
won't get the same number with terminal command stat on this system. (But they are the same on older MacBook)Btw,
fs.realpath.native
works well.The text was updated successfully, but these errors were encountered: