Skip to content

Commit

Permalink
fix: don't eat uncaught exceptions in bootloader
Browse files Browse the repository at this point in the history
Fixes #462
  • Loading branch information
connor4312 committed May 12, 2020
1 parent 35bb73e commit 69d04a5
Show file tree
Hide file tree
Showing 6 changed files with 432 additions and 246 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"fmt": "gulp format",
"package": "gulp package",
"publish": "gulp publish",
"updatetypes": "cd src/typings && vscode-dts dev && vscode-dts master",
"test": "gulp && npm-run-all --parallel test:golden test:lint",
"test:golden": "node ./out/src/test/runTest.js",
"test:lint": "gulp lint"
Expand Down
5 changes: 5 additions & 0 deletions src/targets/node/autoAttachLauncher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ export class AutoAttachLauncher extends NodeLauncherBase<ITerminalLaunchConfigur
cwd: string | undefined,
canUseSpacesInBootloaderPath: boolean,
) {
// Use the local bootloader in development mode for easier iteration
if (this.extensionContext.extensionMode !== vscode.ExtensionMode.Release) {
return super.getBootloaderFile(cwd, canUseSpacesInBootloaderPath);
}

const storagePath =
this.extensionContext.storagePath || this.extensionContext.globalStoragePath;
if (!canUseSpacesInBootloaderPath && storagePath.includes(' ')) {
Expand Down
49 changes: 27 additions & 22 deletions src/targets/node/bootloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as path from 'path';
import { spawnWatchdog } from './watchdogSpawn';
import { IProcessTelemetry } from './nodeLauncherBase';
import { LogTag } from '../../common/logging';
import { installUnhandledErrorReporter } from '../../telemetry/unhandledErrorReporter';
import { onUncaughtError, ErrorType } from '../../telemetry/unhandledErrorReporter';
import { NullTelemetryReporter } from '../../telemetry/nullTelemetryReporter';
import { checkAll } from './bootloader/filters';
import { bootloaderEnv, IBootloaderEnvironment, IAutoAttachInfo } from './bootloader/environment';
Expand All @@ -25,27 +25,32 @@ const telemetry: IProcessTelemetry = {
};

(() => {
installUnhandledErrorReporter(bootloaderLogger, new NullTelemetryReporter());

const env = bootloaderEnv;
bootloaderLogger.info(LogTag.RuntimeLaunch, 'Bootloader imported', { env, args: process.argv });
if (!checkAll(env)) {
env.NODE_INSPECTOR_IPC = undefined; // save work for any children
return;
}

reportTelemetry();

if (/(\\|\/|^)node(64)?(.exe)?$/.test(process.execPath)) {
env.NODE_INSPECTOR_EXEC_PATH = process.execPath;
}

inspectOrQueue(env);

if (env.VSCODE_DEBUGGER_ONLY_ENTRYPOINT === 'true') {
bootloaderEnv.NODE_INSPECTOR_IPC = undefined;
} else {
env.NODE_INSPECTOR_PPID = String(process.pid);
try {
const env = bootloaderEnv;
bootloaderLogger.info(LogTag.RuntimeLaunch, 'Bootloader imported', { env, args: process.argv });
if (!checkAll(env)) {
env.NODE_INSPECTOR_IPC = undefined; // save work for any children
return;
}

reportTelemetry();

if (/(\\|\/|^)node(64)?(.exe)?$/.test(process.execPath)) {
env.NODE_INSPECTOR_EXEC_PATH = process.execPath;
}

inspectOrQueue(env);

if (env.VSCODE_DEBUGGER_ONLY_ENTRYPOINT === 'true') {
bootloaderEnv.NODE_INSPECTOR_IPC = undefined;
} else {
env.NODE_INSPECTOR_PPID = String(process.pid);
}
} catch (e) {
console.error(
`Error in the js-debug bootloader, please report to https://aka.ms/js-dbg-issue: ${e.stack}`,
);
onUncaughtError(bootloaderLogger, new NullTelemetryReporter(), ErrorType.Exception);
}
})();

Expand Down
41 changes: 23 additions & 18 deletions src/telemetry/unhandledErrorReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,17 @@ import { ITelemetryReporter } from './telemetryReporter';
import { LogTag, ILogger } from '../common/logging';
import { IDisposable } from '../common/disposable';

export const enum ErrorType {
Exception = 'uncaughtException',
Rejection = 'unhandledRejection',
}

export function installUnhandledErrorReporter(
logger: ILogger,
telemetryReporter: ITelemetryReporter,
): IDisposable {
const exceptionListener = (exception: unknown) => {
if (shouldReportThisError(exception)) {
telemetryReporter.report('error', {
'!error': exception,
exceptionType: 'uncaughtException',
});
logger.error(LogTag.RuntimeException, 'Unhandled error in debug adapter', exception);
}
};
const rejectionListener = (rejection: unknown) => {
if (shouldReportThisError(rejection)) {
telemetryReporter.report('error', {
'!error': rejection,
exceptionType: 'unhandledRejection',
});
logger.error(LogTag.RuntimeException, 'Unhandled promise rejection', rejection);
}
};
const exceptionListener = onUncaughtError(logger, telemetryReporter, ErrorType.Exception);
const rejectionListener = onUncaughtError(logger, telemetryReporter, ErrorType.Rejection);

process.addListener('uncaughtException', exceptionListener);
process.addListener('unhandledRejection', rejectionListener);
Expand All @@ -41,6 +30,22 @@ export function installUnhandledErrorReporter(
};
}

export const onUncaughtError = (
logger: ILogger,
telemetryReporter: ITelemetryReporter,
src: ErrorType,
) => (error: unknown) => {
if (!shouldReportThisError(error)) {
return;
}

telemetryReporter.report('error', {
'!error': error,
exceptionType: src,
});
logger.error(LogTag.RuntimeException, 'Unhandled error in debug adapter', error);
};

const isErrorObjectLike = (err: unknown): err is Error =>
typeof err === 'object' && !!err && 'stack' in err;

Expand Down
Loading

0 comments on commit 69d04a5

Please sign in to comment.