Skip to content

Workspace enumeration follows symlinks out of the workspace: wine prefix dosdevices/z: -> / pins a CPU core at 100% and floods the log #5620

Description

Type: Performance Issue

Summary

The PowerShell language server (PSES) recursively enumerates the whole workspace on startup looking for .ps1/.psm1/.psd1 files, and follows directory symlinks with no containment or cycle check. A single symlink pointing to the filesystem root — e.g. a standard Wine prefix inside the workspace, which always contains dosdevices/z: -> / — makes the walk effectively unbounded: PSES pins one CPU core at ~100% indefinitely and floods its log (~5 MB every 1–2 minutes) with Could not enumerate directories in the path '…' due to the path not being accessible warnings. Removing the symlink is not enough by itself — the already running enumeration never finishes; the session has to be restarted.

Environment

  • Extension version: 2025.4.0
  • VS Code version: 1.140.0
  • OS version: macOS 26.7.1, arm64
  • PowerShell version: 7.6.6

Repro

  1. Put a standard Wine prefix inside the workspace (any folder where one runs/tests Windows tools; it does not even need to be tracked by git — the enumerator does not consult .gitignore):
    WINEPREFIX=<workspace>/Temp/wine-prefix wineboot --init
    ls -l <workspace>/Temp/wine-prefix/dosdevices
    # c: -> ../drive_c
    # z: -> /          <-- auto-created by wine for every prefix
    
  2. Open the workspace in VS Code with the PowerShell extension and open any .ps1 file.

Observed

  • The pwsh (PSES) process sits at ~100% of one core for hours (verified over 1.5 h; it had accumulated 72 minutes of CPU time by the time I sampled it).
  • The PSES log rotates every 1–2 minutes at ~5 MB per file, almost entirely entries like:
    <Warning>Microsoft.PowerShell.EditorServices.Services.WorkspaceService: Could not enumerate directories in the path '/Users/…/Temp/wine-prefix/dosdevices/z:/…' due to the path not being accessible
    
    The logged paths show the walker descending into z: and re-entering the workspace through nested z: segments.
  • sample <pid> shows a single .NET thread-pool worker spending ~100% of its samples in filesystem enumeration syscalls: SystemNative_OpenDir / SystemNative_ReadDir / SystemNative_Stat / SystemNative_LStat.

Root cause

  • WorkspaceService.FollowSymlinks defaults to true, so EnumeratePSFiles() runs with ignoreReparsePoints: false and maxDepth: 64: WorkspaceService.cs.
  • WorkspaceFileSystemWrapper.SafeEnumerateFileSystemInfos applies only that MaxRecursionDepth cap — the mitigation added in PowerShellEditorServices#795 for Process terminated bue to StackOverFlow - process terminated with code 3221225725 #1613: WorkspaceFileSystemWrapper.cs. A depth cap bounds nesting, but not breadth or revisits: a z: -> / link lets the walker enumerate the entire filesystem, and since / contains the workspace itself, the walk re-enters dosdevices/z: again and again up to the depth limit — in practice unbounded work on a real disk.

Workaround

rm "<workspace>/Temp/wine-prefix/dosdevices/z:"

then restart the session (PowerShell: Restart Current Session or reload the window). Wine itself works fine without the Z: drive, so the symlink can safely be deleted right after prefix creation (and re-deleted whenever the prefix is re-initialized).

Possible directions

  • Don't follow directory symlinks whose resolved target is outside the workspace roots (containment check), and/or
  • detect cycles (e.g. a visited (device, inode) set for symlinked directories), and/or
  • default FollowSymlinks to false, or expose it as a user setting,
  • optionally consult .gitignore — in my case the indexer burned a core over a Temp/ folder that git itself ignores.

Happy to test a build with any of these.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions