vscode-cpptools icon indicating copy to clipboard operation
vscode-cpptools copied to clipboard

externalTerminal console does not launch when path includes spaces

Open adaml-at-eargo opened this issue 1 year ago • 8 comments

Type: Bug

  1. Create a debug launch configuration that uses the externalTerminal console type and make it the currently selected debug configuration.
  2. Launch the debugger.
  3. An external window will appear with an error message similar to this (note the quoting of path elements with spaces):
[error 2147942402 (0x80070002) when launching `Lins\AppData\Local\Microsoft\WindowsApps\wt.exe 
-d C:\WINDOWS\System32\cmd.exe /c c:\Users\Adam "Lins\.vscode\extensions\ms-vscode.cpptools-1.18.5-win32-x64\debugAdapters\vsdbg\bin\VsDebugConsole.exe 
\\.\pipe\Microsoft-VisualStudio-Debug-Console-{4378F327-15AB-4D47-BC0B-45CB6D2FF806} 
Local\{4378F327-15AB-4D47-BC0B-45CB6D2FF806} /AutoExit & pause"']
  1. In VSCode, the debug control panel will appear as well as an error message pop-up noting that the target application cannot be started.

Extension version: 1.18.5 VS Code version: Code 1.86.1 (31c37ee8f63491495ac49e43b8544550fbae4533, 2024-02-07T09:08:20.941Z) OS version: Windows_NT x64 10.0.22631 Modes:

System Info
Item Value
CPUs 12th Gen Intel(R) Core(TM) i7-1265U (12 x 2688)
GPU Status 2d_canvas: enabled
canvas_oop_rasterization: enabled_on
direct_rendering_display_compositor: disabled_off_ok
gpu_compositing: enabled
multiple_raster_threads: enabled_on
opengl: enabled_on
rasterization: enabled
raw_draw: disabled_off_ok
skia_graphite: disabled_off
video_decode: enabled
video_encode: enabled
vulkan: disabled_off
webgl: enabled
webgl2: enabled
webgpu: enabled
Load (avg) undefined
Memory (System) 15.44GB (5.34GB free)
Process Argv ..\..\.local\tenpo.code-workspace --crash-reporter-id 0312ea16-4d0d-401e-92c7-0bd47ce3b3fd
Screen Reader no
VM 0%
A/B Experiments
vsliv368cf:30146710
vspor879:30202332
vspor708:30202333
vspor363:30204092
vswsl492:30256859
vscod805:30301674
binariesv615:30325510
vsaa593cf:30376535
py29gd2263:30899288
c4g48928:30535728
azure-dev_surveyone:30548225
2i9eh265:30646982
962ge761:30959799
pythongtdpath:30769146
welcomedialogc:30910334
pythonidxpt:30866567
pythonnoceb:30805159
asynctok:30898717
pythontestfixt:30902429
pythonregdiag2:30936856
pyreplss1:30897532
pythonmypyd1:30879173
pythoncet0:30885854
pythontbext0:30879054
accentitlementsc:30887149
dsvsc016:30899300
dsvsc017:30899301
dsvsc018:30899302
b5d27386:30958190
a89i1917:30961429
3ef8e399:30964150
e3gdj431:30958358

adaml-at-eargo avatar Feb 14 '24 23:02 adaml-at-eargo

Have you attempted to launch the console with a path that doesn't include spaces? This may be due to our shell quoting logic as it should be applying shell quoting to your arguments whenever a special character is present such as a space or backslash.

browntarik avatar Feb 15 '24 18:02 browntarik

I first noticed this issue after changing laptops, which also migrated me from Windows 10 to Windows 11. My %USERPROFILE% path on Windows 10 didn't have a space in it; on Windows 11, it does.

I don't think I can (safely) change my user account folder to remove the space or add a new user to this machine. Which makes it hard to test launching the debugger with an external terminal using a profile that doesn't have a space in the path.

adaml-at-eargo avatar Feb 15 '24 19:02 adaml-at-eargo

Ok, given that context, I believe this may be the result of a VS Code Bug: https://github.com/microsoft/vscode/issues/204039

This should be fixed if you download the latest VS Code Insiders. Could you give that a try? https://code.visualstudio.com/insiders/

browntarik avatar Feb 15 '24 19:02 browntarik

I tried v1.87.0-insider with the same result: the space in the %USERPROFILE% path isn't being handled correctly, causing a debug session with console type externalTerminal to fail.

Version: 1.87.0-insider (user setup) Commit: e587755905208e47725c5196539c4ca898255fe6 Date: 2024-02-15T05:47:14.979Z Electron: 27.3.2 ElectronBuildId: 26836302 Chromium: 118.0.5993.159 Node.js: 18.17.1 V8: 11.8.172.18-electron.0 OS: Windows_NT x64 10.0.22631

adaml-at-eargo avatar Feb 15 '24 21:02 adaml-at-eargo

This issue is still happening on Windows 10 in v1.88.1 of vscode with v1.19.9 of cpptools.

This launch config:

{
    "type": "cppvsdbg",
    "name": "Run (Debug)",
    "request": "launch",
    "program": "${workspaceFolder}/build/Debug/bin/AppName.exe",
    "stopAtEntry": false,
    "cwd": "${workspaceFolder}/dev",
    "environment": [],
    "console": "externalTerminal",
    "preLaunchTask": "Build Debug"
}

results in this error when the user folder has a space in the name:

[error 2147942402 (0x80070002) when launching `LastName\AppData\Local\Microsoft\WindowsApps\wt.exe -d . C:\Windows\System32\cmd.exe /c "c:\Users\FirstName LastName\.vscode\extensions\ms-vscode.cpptools-1.19.9-win32-x64\debugAdapters\vsdbg\bin\VsDebugConsole.exe" \\.\pipe\Microsoft-VisualStudio-Debug-Console-{586864FF-B80E-4F29-9E79-2B32A189984F} Local\{586864FF-B80E-4F29-9E79-2B32A189984F} /AutoExit & pause']

ndalton577 avatar May 01 '24 15:05 ndalton577

TL;DR: Workarounds:

  • Option 1 (recommended): Set Terminal > External: Windows Exec to wt

  • Option 2: Change console from externalTerminal to internalConsole


I am getting the same error:

[error 2147942402 (0x80070002) when launching `Livingston\AppData\Local\Microsoft\WindowsApps\wt.exe -d . C:\WINDOWS\System32\cmd.exe /c "c:\Users\Daniel Livingston.vscode\extensions\ms-vscode.cpptools-1.19.9-win32-x64\debugAdapters\vsdbg\bin\VsDebugConsole.exe" \.\pipe\Microsoft-VisualStudio-Debug-Console-{C4B324D0-B6B6-4ECF-89D6-2BE2737ED7E1} Local{C4B324D0-B6B6-4ECF-89D6-2BE2737ED7E1} /AutoExit & pause']

The path should be 'C:\Users\Daniel Livingston\AppData\Local\Microsoft\WindowsApps\wt.exe'.

I'm pretty sure things are going wrong in vscode/src/vs/platform/externalTerminal/node/externalTerminalService.ts:

public async runInTerminal(title: string, dir: string, args: string[], envVars: ITerminalEnvironment, settings: IExternalTerminalSettings): Promise<number | undefined> {
	const exec = 'windowsExec' in settings && settings.windowsExec ? settings.windowsExec : WindowsExternalTerminalService.getDefaultTerminalWindows();
	const wt = await WindowsExternalTerminalService.getWtExePath();

	return new Promise<number | undefined>((resolve, reject) => {

		const title = `"${dir} - ${TERMINAL_TITLE}"`;
		const command = `"${args.join('" "')}" & pause`; // use '|' to only pause on non-zero exit code

		// merge environment variables into a copy of the process.env
		const env = Object.assign({}, getSanitizedEnvironment(process), envVars);

		// delete environment variables that have a null value
		Object.keys(env).filter(v => env[v] === null).forEach(key => delete env[key]);

		const options: any = {
			cwd: dir,
			env: env,
			windowsVerbatimArguments: true
		};

		let spawnExec: string;
		let cmdArgs: string[];

		if (path.basename(exec, '.exe') === 'wt') {
			// Handle Windows Terminal specially; -d to set the cwd and run a cmd.exe instance
			// inside it
			spawnExec = exec;
			cmdArgs = ['-d', '.', WindowsExternalTerminalService.CMD, '/c', command];
		} else if (wt) {
			// prefer to use the window terminal to spawn if it's available instead
			// of start, since that allows ctrl+c handling (#81322)
			spawnExec = wt;
			cmdArgs = ['-d', '.', exec, '/c', command];
		} else {
			spawnExec = WindowsExternalTerminalService.CMD;
			cmdArgs = ['/c', 'start', title, '/wait', exec, '/c', `"${command}"`];
		}

		const cmd = cp.spawn(spawnExec, cmdArgs, options);

		cmd.on('error', err => {
			reject(improveError(err));
		});

		resolve(undefined);
	});
}

Note the if (path.basename(exec, '.exe') === 'wt') line: exec comes from the setting Terminal > External: Windows Exec. Hence my Option 1 solution: explicitly setting this to wt means that:

const cmd = cp.spawn(spawnExec, cmdArgs, options);

evaluates to:

const cmd = cp.spawn("wt", ...);

So, if Windows Exec is set to anything else (including the default of cmd.exe), it instead evaluates to:

const cmd = cp.spawn(WindowsExternalTerminalService.getWtExePath(), ...);

Either spawn isn't escaping spaces in paths or getWtExePath is returning malformed.

daniellivingston avatar May 02 '24 21:05 daniellivingston