From 96bd5f640b01caaba5028875ffa1367142afb0a4 Mon Sep 17 00:00:00 2001 From: Dmitriy Vasyura Date: Thu, 1 Jan 2026 16:48:44 -0800 Subject: [PATCH 1/2] Do not assume stdout/stderr are defined when spawning a child process. --- extensions/git/src/git.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 3fb80e0ee98..b5be1268884 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -2684,19 +2684,23 @@ export class Repository { if (limit !== 0 && parser.status.length > limit) { child.removeListener('close', onClose); - child.stdout!.removeListener('data', onStdoutData); + child.stdout?.removeListener('data', onStdoutData); child.kill(); c({ status: parser.status.slice(0, limit), statusLength: parser.status.length, didHitLimit: true }); } }; - child.stdout!.setEncoding('utf8'); - child.stdout!.on('data', onStdoutData); + if (child.stdout) { + child.stdout.setEncoding('utf8'); + child.stdout.on('data', onStdoutData); + } const stderrData: string[] = []; - child.stderr!.setEncoding('utf8'); - child.stderr!.on('data', raw => stderrData.push(raw as string)); + if (child.stderr) { + child.stderr.setEncoding('utf8'); + child.stderr.on('data', raw => stderrData.push(raw as string)); + } child.on('error', cpErrorHandler(e)); child.on('close', onClose); From be8b8bfdcc7e73ebecc74cc4227af5df1e313c95 Mon Sep 17 00:00:00 2001 From: Dmitriy Vasyura Date: Fri, 2 Jan 2026 16:47:47 -0800 Subject: [PATCH 2/2] Add more stdio checks when spawning git processes. --- extensions/git/src/git.ts | 10 +++++++++- extensions/git/src/repository.ts | 22 +++++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index b5be1268884..f17163f9f55 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -1924,7 +1924,15 @@ export class Repository { async stage(path: string, data: Uint8Array): Promise { const relativePath = this.sanitizeRelativePath(path); const child = this.stream(['hash-object', '--stdin', '-w', '--path', relativePath], { stdio: [null, null, null] }); - child.stdin!.end(data); + + if (!child.stdin) { + throw new GitError({ + message: 'Failed to spawn git process', + exitCode: -1 + }); + } + + child.stdin.end(data); const { exitCode, stdout } = await exec(child); const hash = stdout.toString('utf8'); diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 7977887182f..0e733707674 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -2347,7 +2347,15 @@ export class Repository implements Disposable { // https://git-scm.com/docs/git-check-ignore#git-check-ignore--z const child = this.repository.stream(['check-ignore', '-v', '-z', '--stdin'], { stdio: [null, null, null] }); - child.stdin!.end(filePaths.join('\0'), 'utf8'); + + if (!child.stdin) { + return reject(new GitError({ + message: 'Failed to spawn git process', + exitCode: -1 + })); + } + + child.stdin.end(filePaths.join('\0'), 'utf8'); const onExit = (exitCode: number) => { if (exitCode === 1) { @@ -2369,12 +2377,16 @@ export class Repository implements Disposable { data += raw; }; - child.stdout!.setEncoding('utf8'); - child.stdout!.on('data', onStdoutData); + if (child.stdout) { + child.stdout.setEncoding('utf8'); + child.stdout.on('data', onStdoutData); + } let stderr: string = ''; - child.stderr!.setEncoding('utf8'); - child.stderr!.on('data', raw => stderr += raw); + if (child.stderr) { + child.stderr.setEncoding('utf8'); + child.stderr.on('data', raw => stderr += raw); + } child.on('error', reject); child.on('exit', onExit);