Skip to content

fix(real-path): ask the kernel about a trailing slash after a symlink - #775

Closed
konsta95 wants to merge 1 commit into
anthropics:mainfrom
konsta95:fix/real-path-trailing-slash
Closed

konsta95 wants to merge 1 commit into
anthropics:mainfrom
konsta95:fix/real-path-trailing-slash

Conversation

@konsta95

Copy link
Copy Markdown

Problem

On macOS 14 and 15, link/ opens the file when link points to a file. Linux and macOS 26 refuse the same path with ENOTDIR. wayTo always applied the Linux rule, so on macOS 14 and 15 realPathOf disagreed with the kernel. That made the property: realPathOf test fail now and then in CI, sometimes as a 120 s timeout while fast-check was shrinking the case.

The difference is in the kernel source. In macOS 14 and 15, xnu's vfs_cache.c clears the trailing-slash flag after it follows a link. The macOS 26 source no longer does.

Fix

When a followed link has only slashes after it, wayTo now asks the kernel with stat("<link>/"):

  • If the stat succeeds, the slash is dropped and the walk continues into the link's target.
  • If it fails, nothing changes. The walk returns the same error or partial result as before, so ELOOP, EILSEQ and the partial return all stay as they were.

The property test now includes the error in its report. A run still going at 90 s counts as a failure, so the test no longer runs into its 120 s timeout.

Tests

New cases in test/utils/real-path.test.ts:

  • a slash after a link to a file, to a directory and to an absolute path, each compared with what the kernel says
  • a faked successful probe, so Linux CI also catches the fix being removed
  • ELOOP after 40 links, EILSEQ, and the partial return, all unchanged

Checked

  • On real macOS runners (my fork, 3 runs each), the new kernel test fails with the old code and passes with the fix, on both macOS 14.8.9 (arm64) and macOS 15.7.9 (Intel).
  • On macOS 14, the property test passed 495 of 495 repeat runs.
  • On Linux, the full suite shows no new failures, and the new tests pass.
  • Not checked: a repeat count on macOS 15. The standard Intel runner was too slow for my time budget.

Overlap

#693 and #737 change the same lines in wayTo, so whichever lands second needs a small rebase. If #737 lands first, the probe should go through its asked() helper.

🤖 Generated with Claude Code, reviewed by Elias.

macOS 14 and 15 drop a trailing slash after a followed symlink (xnu
clears NAMEI_TRAILINGSLASH), so link-to-file/ resolves to the file,
while Linux and macOS 26 answer ENOTDIR. wayTo always applied the
Linux rule, so the realPathOf property failed intermittently on macOS
14/15 and could time out while fast-check shrank the failure.

A stat probe of <link>/ now decides. When it succeeds the trailing
slash is dropped; when it fails the walk keeps its own error and
partial result, so ELOOP, EILSEQ and wayTo's partial return stay as
they were. The property now puts its error in the report, and a run
still going at 90 s counts as a failure, before the 120 s timeout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: a68131fc-e1c6-45c2-9cf6-4d99438fbf1d
@konsta95 konsta95 closed this Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant