From 64bc0d0a427fe52ae52e9cc481766fc7151b5746 Mon Sep 17 00:00:00 2001 From: orca-bug-scan-bot Date: Sat, 11 Jul 2026 14:43:45 -0700 Subject: [PATCH] fix: address pr-bug-scan validated finding from #7969 Replaced synchronous execFileSync('wsl.exe') with async execFile off-thread + cache; canonicalizeWslLinuxPath now returns cached-or-null synchronously, so the main-process launch path never blocks. --- src/main/codex/codex-wsl-hook-install-plan.ts | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/main/codex/codex-wsl-hook-install-plan.ts b/src/main/codex/codex-wsl-hook-install-plan.ts index e7878777bff..bb141251bdf 100644 --- a/src/main/codex/codex-wsl-hook-install-plan.ts +++ b/src/main/codex/codex-wsl-hook-install-plan.ts @@ -1,4 +1,4 @@ -import { execFileSync } from 'node:child_process' +import { execFile } from 'node:child_process' import { win32 as pathWin32 } from 'node:path' import { parseWslUncPath } from '../../shared/wsl-paths' @@ -29,24 +29,43 @@ function toDefaultWslLinuxPath(windowsPath: string): string { return `/mnt/${driveMatch[1].toLowerCase()}/${driveMatch[2].replace(/\\/g, '/')}` } +const WSL_CANONICALIZE_TIMEOUT_MS = 5000 + +// Why: `readlink -f` over wsl.exe stalls up to the timeout on a cold or wedged +// distro. Running it synchronously (execFileSync) on the Electron main process +// froze the UI on every Codex WSL launch, so resolve it off-thread and return +// the cached result synchronously (null until the first resolution lands). +const canonicalWslPathCache = new Map() +const inFlightWslCanonicalizations = new Set() + +function wslCanonicalizeCacheKey(distro: string, linuxPath: string): string { + return `${distro}\x00${linuxPath}` +} + function canonicalizeWslLinuxPath(distro: string, linuxPath: string): string | null { if (process.platform !== 'win32') { return linuxPath } - try { - const canonicalPath = execFileSync( + const key = wslCanonicalizeCacheKey(distro, linuxPath) + if (!inFlightWslCanonicalizations.has(key)) { + inFlightWslCanonicalizations.add(key) + execFile( 'wsl.exe', ['-d', distro, '--', 'readlink', '-f', '--', linuxPath], - { - encoding: 'utf-8', - stdio: ['ignore', 'pipe', 'ignore'], - timeout: 5000 + { encoding: 'utf-8', timeout: WSL_CANONICALIZE_TIMEOUT_MS, windowsHide: true }, + (error, stdout) => { + inFlightWslCanonicalizations.delete(key) + const canonicalPath = stdout.trim() + if (!error && canonicalPath.startsWith('/')) { + canonicalWslPathCache.set(key, canonicalPath) + } } - ).trim() - return canonicalPath.startsWith('/') ? canonicalPath : null - } catch { - return null + ) } + // Why: return the cached canonical path (or null on the first launch, which + // falls back to the logical path) so plan building stays synchronous without + // blocking the main thread on the wsl.exe subprocess. + return canonicalWslPathCache.get(key) ?? null } export function createCodexWslRuntimeHookInstallPlan(