Skip to content

Fix slow app scan on macOS 26 caused by implicit lstat in URL.appendi…#574

Open
RayaCoo wants to merge 1 commit into
alienator88:mainfrom
RayaCoo:fix-implicit-lstat
Open

Fix slow app scan on macOS 26 caused by implicit lstat in URL.appendi…#574
RayaCoo wants to merge 1 commit into
alienator88:mainfrom
RayaCoo:fix-implicit-lstat

Conversation

@RayaCoo

@RayaCoo RayaCoo commented May 11, 2026

Copy link
Copy Markdown

Problem

App scan stalls 30+ seconds at Scanning N system locations... on macOS 26. Sample shows 100% of CPU in lstat, called implicitly by URL.appendingPathComponent:

processLocation
  URL.appendingPathComponent
    _SwiftURL.appending(path:directoryHint:…)
      lstat

appendingPathComponent(_:) (without an explicit isDirectory argument) consults the filesystem to decide whether to treat the result as a directory — this behavior is documented but easy to miss. The
proposal author noted it when DirectoryHint was introduced:

"URL will try to consult the filesystem (aka lstat) to determine whether the URL refers to a directory when you call the variants of methods and file path constructors that do not have the explicit
isDirectory parameter."
Foundation URL Improvements, Swift Forums

AppPathFinder.processLocation and ReversePathsSearcher.processLocation call this on every directory entry inside their inner scan loops. With ~5000 entries across ~/Library/Containers, Application
Support, Caches, etc., the redundant lstats dominate scan time — and the immediately-following fileExists(atPath:isDirectory:) does the real directory check anyway.

Fix

Replace .appendingPathComponent(x) with .appending(path: x, directoryHint: .notDirectory) at the four hot-loop call sites. .notDirectory only affects the URL string (trailing slash); downstream
fileExists(atPath:isDirectory:) is authoritative. Behavior unchanged.

Scans that previously took 30+ seconds complete in ~1 second on macOS 26.4.1.

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