From f1306c94fe30a238dbeeb62e907730fc7d07d834 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Mon, 11 Dec 2023 13:04:17 -0800 Subject: [PATCH 1/2] fix: show errors from cond bps, don't pause on internal exceptions Fixes https://github.com/microsoft/vscode/issues/195062 --- CHANGELOG.md | 2 ++ .../breakpoints/conditions/expression.ts | 8 +++--- src/adapter/exceptionPauseService.ts | 17 ++++++++++-- src/adapter/sourceContainer.ts | 22 ++++++++++++---- src/adapter/threads.ts | 26 ++++++++++--------- ...nts-condition-ignores-error-by-default.txt | 11 ++++++++ .../breakpoints-condition-pauses-on-error.txt | 2 +- src/test/breakpoints/breakpointsTest.ts | 2 ++ ...s-not-pause-on-exceptions-in-internals.txt | 1 + src/test/threads/threadsTest.ts | 20 ++++++++++++++ 10 files changed, 86 insertions(+), 25 deletions(-) create mode 100644 src/test/threads/threads-pause-on-exceptions-does-not-pause-on-exceptions-in-internals.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index c82a6600c..5b45cb632 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ This changelog records changes to stable releases since 1.50.2. "TBA" changes he ## Nightly (only) +- fix: show errors from conditional breakpoints ([vscode#195062](https://github.com/microsoft/vscode/issues/195062)) +- fix: pausing on exceptions caused by internal scripts ([vscode#195062](https://github.com/microsoft/vscode/issues/195062)) - fix: automatically reconnect when debugging browsers in port mode ([vscode#174033](https://github.com/microsoft/vscode/issues/174033)) ## v1.85 (November 2023) diff --git a/src/adapter/breakpoints/conditions/expression.ts b/src/adapter/breakpoints/conditions/expression.ts index dcfd39a49..53f1cd594 100644 --- a/src/adapter/breakpoints/conditions/expression.ts +++ b/src/adapter/breakpoints/conditions/expression.ts @@ -20,9 +20,7 @@ export class ExpressionCondition implements IBreakpointCondition { breakOnError: boolean, evaluator: IEvaluator, ) { - if (breakOnError) { - breakCondition = wrapBreakCondition(breakCondition); - } + breakCondition = wrapBreakCondition(breakCondition, breakOnError); const err = breakCondition && getSyntaxErrorIn(breakCondition); if (err) { @@ -61,5 +59,5 @@ export class ExpressionCondition implements IBreakpointCondition { } } -export const wrapBreakCondition = (condition: string) => - `(()=>{try{return ${condition};}catch(e){console.error(e);return true}})()`; +export const wrapBreakCondition = (condition: string, breakOnError: boolean) => + `(()=>{try{return ${condition};}catch(e){console.error(\`Breakpoint condition error: \${e.message||e}\`);return ${!!breakOnError}}})()`; diff --git a/src/adapter/exceptionPauseService.ts b/src/adapter/exceptionPauseService.ts index d370aec6b..3762b8857 100644 --- a/src/adapter/exceptionPauseService.ts +++ b/src/adapter/exceptionPauseService.ts @@ -6,7 +6,7 @@ import { inject, injectable } from 'inversify'; import Cdp from '../cdp/api'; import { truthy } from '../common/objUtils'; import { getDeferred } from '../common/promiseUtil'; -import { getSyntaxErrorIn } from '../common/sourceUtils'; +import { SourceConstants, getSyntaxErrorIn } from '../common/sourceUtils'; import { AnyLaunchConfiguration } from '../configuration'; import Dap from '../dap/api'; import { IDapApi } from '../dap/connection'; @@ -120,6 +120,19 @@ export class ExceptionPauseService implements IExceptionPauseService { return false; } + // If there's an internal frame anywhere in the stack, this call is from + // some internally-executed script not visible for the user. Never pause + // if this results in an exception: the caller should handle it. + if ( + evt.callFrames.some(cf => + this.sourceContainer + .getSourceScriptById(cf.location.scriptId) + ?.url.endsWith(SourceConstants.InternalExtension), + ) + ) { + return false; + } + if (this.shouldScriptSkip(evt)) { return false; } @@ -233,7 +246,7 @@ export class ExceptionPauseService implements IExceptionPauseService { ); } - const wrapped = this.breakOnError ? wrapBreakCondition(expr) : expr; + const wrapped = wrapBreakCondition(expr, this.breakOnError); return this.evaluator.prepare(wrapped, { hoist: ['error'] }).invoke; }; diff --git a/src/adapter/sourceContainer.ts b/src/adapter/sourceContainer.ts index 8f376fa5a..39d8bfb13 100644 --- a/src/adapter/sourceContainer.ts +++ b/src/adapter/sourceContainer.ts @@ -30,6 +30,7 @@ import { IScriptSkipper } from './scriptSkipper/scriptSkipper'; import { ContentGetter, ISourceMapLocationProvider, + ISourceScript, ISourceWithMap, IUiLocation, LineColumn, @@ -139,7 +140,7 @@ export class SourceContainer { /** * Mapping of CDP script IDs to Script objects. */ - private readonly scriptsById: Map = new Map(); + private readonly scriptsById: Map = new Map(); private onSourceMappedSteppingChangeEmitter = new EventEmitter(); private onScriptEmitter = new EventEmitter