Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/extension/debugger/attachQuickPick/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

'use strict';

import { l10n } from 'vscode';
import * as path from 'path';
import { env, l10n } from 'vscode';
import type { IProcessInfo } from '@vscode/windows-process-tree';
import { getOSType, OSType } from '../../common/platform';
import { PsProcessParser } from './psProcessParser';
Expand All @@ -16,6 +17,14 @@ import { logProcess } from '../../common/process/logger';
export class AttachProcessProvider implements IAttachProcessProvider {
constructor() {}

public _loadWindowsProcessTree(): typeof import('@vscode/windows-process-tree') {
const wpcPath = path.join(env.appRoot, 'node_modules', '@vscode', 'windows-process-tree');
// Use eval to bypass webpack's require interception for loading native addon at runtime
// eslint-disable-next-line no-eval
const nodeRequire = eval('require') as NodeJS.Require;
return nodeRequire(wpcPath);
}

public getAttachItems(): Promise<IAttachItem[]> {
return this._getInternalProcessEntries().then((processEntries) => {
processEntries.sort(
Expand Down Expand Up @@ -63,7 +72,7 @@ export class AttachProcessProvider implements IAttachProcessProvider {

if (osType === OSType.Windows) {
try {
const wpc = require('@vscode/windows-process-tree');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the way this is handled for other stuff is that VS code would intercept the require and return their implementation. Perhaps they don't do that for windows-process-tree though. I recall this happening for things like the 'vscode' package itself.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the way this is handled for other stuff is that VS code would intercept the require and return their implementation. Perhaps they don't do that for windows-process-tree though. I recall this happening for things like the 'vscode' package itself.

Yep, I found out other modules like @vscode/extension-telemetry, VS Code's loader does exactly that and intercepts the require call.

Maybe, @vscode/windows-process-tree is a bit of a special case because it’s a native addon containing a .node binary? Since it involves loading machine code that is highly sensitive to the specific OS architecture and Node ABI, it doesn't seem to be part of that standard interception layer. Loading it via appRoot ensures we're hitting the actual binary that matches the running VS Code instance.

const wpc = this._loadWindowsProcessTree();
const processList = await new Promise<IProcessInfo[]>((resolve) => {
wpc.getAllProcesses(
(processes: IProcessInfo[]) => resolve(processes),
Expand Down
8 changes: 6 additions & 2 deletions src/test/unittest/attachQuickPick/provider.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { IAttachItem } from '../../../extension/debugger/attachQuickPick/types';
import { WmicProcessParser } from '../../../extension/debugger/attachQuickPick/wmicProcessParser';
import * as platform from '../../../extension/common/platform';
import * as rawProcessApis from '../../../extension/common/process/rawProcessApis';
import * as wpc from '@vscode/windows-process-tree';

use(chaiAsPromised);

Expand All @@ -27,7 +26,12 @@ suite('Attach to process - process provider', () => {
provider = new AttachProcessProvider();
getOSTypeStub = sinon.stub(platform, 'getOSType');
plainExecStub = sinon.stub(rawProcessApis, 'plainExec');
getAllProcessesStub = sinon.stub(wpc, 'getAllProcesses');
getAllProcessesStub = sinon.stub();
sinon.stub(provider, '_loadWindowsProcessTree').returns({
getAllProcesses: getAllProcessesStub,
// eslint-disable-next-line @typescript-eslint/naming-convention
ProcessDataFlag: { None: 0, Memory: 1, CommandLine: 2 },
} as any);
});

teardown(() => {
Expand Down
2 changes: 1 addition & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const extensionConfig = {
'@opentelemetry/instrumentation': 'commonjs @opentelemetry/instrumentation', // ignored because we don't ship instrumentation
'@azure/opentelemetry-instrumentation-azure-sdk': 'commonjs @azure/opentelemetry-instrumentation-azure-sdk', // ignored because we don't ship instrumentation
'@azure/functions-core': '@azure/functions-core', // ignored because we don't ship instrumentation
'@vscode/windows-process-tree': 'commonjs @vscode/windows-process-tree', // native addon (.node binary); webpack cannot bundle it, resolved at runtime via VS Code's built-in copy
'@vscode/windows-process-tree': 'commonjs @vscode/windows-process-tree', // native addon (.node binary); webpack cannot bundle it. Loaded at runtime via vscode.env.appRoot absolute path using eval('require') to bypass webpack's require interception
},
resolve: {
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
Expand Down
Loading