Skip to content

Commit 2914f1e

Browse files
committed
lib: fix infinite loop in fs.realpathSync
Get the link target head realpath. Then resolve realpath and link target tail. Resolve tail after resolving the link head. Fixes: #60295
1 parent 2679b62 commit 2914f1e

File tree

1 file changed

+29
-6
lines changed

1 file changed

+29
-6
lines changed

lib/fs.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2730,17 +2730,29 @@ function realpathSync(p, options) {
27302730
// Walk down the path, swapping out linked path parts for their real
27312731
// values
27322732
// NB: p.length changes.
2733-
while (pos < p.length) {
2734-
// find the next part
2735-
const result = nextPart(p, pos);
2733+
let unresolvedTail = '';
2734+
while (true) {
2735+
if (pos >= p.length) {
2736+
if (unresolvedTail === '') {
2737+
break;
2738+
}
2739+
2740+
p = pathModule.resolve(p + unresolvedTail);
2741+
unresolvedTail = '';
2742+
current = base = splitRoot(p);
2743+
pos = current.length;
2744+
continue;
2745+
}
2746+
2747+
const result = nextPart(p + unresolvedTail, pos);
27362748
previous = current;
27372749
if (result === -1) {
27382750
const last = StringPrototypeSlice(p, pos);
27392751
current += last;
27402752
base = previous + last;
27412753
pos = p.length;
27422754
} else {
2743-
current += StringPrototypeSlice(p, pos, result + 1);
2755+
current += StringPrototypeSlice(p + unresolvedTail, pos, result + 1);
27442756
base = previous + StringPrototypeSlice(p, pos, result);
27452757
pos = result + 1;
27462758
}
@@ -2761,7 +2773,6 @@ function realpathSync(p, options) {
27612773
} else {
27622774
// Use stats array directly to avoid creating an fs.Stats instance just
27632775
// for our internal use.
2764-
27652776
const stats = binding.lstat(base, true, undefined, true /* throwIfNoEntry */);
27662777
if (stats === undefined) {
27672778
return;
@@ -2770,6 +2781,11 @@ function realpathSync(p, options) {
27702781
if (!isFileType(stats, S_IFLNK)) {
27712782
knownHard.add(base);
27722783
cache?.set(base, base);
2784+
if (unresolvedTail !== '') {
2785+
p = pathModule.resolve(p + unresolvedTail);
2786+
unresolvedTail = '';
2787+
}
2788+
27732789
continue;
27742790
}
27752791

@@ -2786,11 +2802,18 @@ function realpathSync(p, options) {
27862802
}
27872803
}
27882804
if (linkTarget === null) {
2805+
debugger;
27892806
binding.stat(base, false, undefined, true);
27902807
linkTarget = binding.readlink(base, undefined);
27912808
}
2792-
resolvedLink = pathModule.resolve(previous, linkTarget);
27932809

2810+
const nextPathDelimiterIndex = nextPart(linkTarget, 0);
2811+
if (nextPathDelimiterIndex >= 1) {
2812+
unresolvedTail = StringPrototypeSlice(linkTarget, nextPathDelimiterIndex) + unresolvedTail;
2813+
linkTarget = StringPrototypeSlice(linkTarget, 0, nextPathDelimiterIndex);
2814+
}
2815+
2816+
resolvedLink = pathModule.resolve(previous, linkTarget);
27942817
cache?.set(base, resolvedLink);
27952818
if (!isWindows) seenLinks.set(id, linkTarget);
27962819
}

0 commit comments

Comments
 (0)