Skip to content

Commit 581f645

Browse files
authored
fix: unbound breakpoints in sourcemaps on Chrome 112 (#1580)
Chrome Dev (112) no longer has any stackframes for instrumentation breakpoints, which was resulting in a thrown error. Fixes #1567
1 parent 87eaa14 commit 581f645

File tree

3 files changed

+27
-24
lines changed

3 files changed

+27
-24
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This changelog records changes to stable releases since 1.50.2. "TBA" changes he
66

77
- fix: repl stacktrace with renames showing too much info ([#1259](https://github.com/microsoft/vscode-js-debug/issues/1259#issuecomment-1409443564))
88
- fix: recursive source map resolution parsing ignored locations ([vscode#169733](https://github.com/microsoft/vscode/issues/169733))
9+
- fix: unbound breakpoints in sourcemaps on Chrome 112 ([#1567](https://github.com/microsoft/vscode-js-debug/issues/1567))
910

1011
## v1.76 (February 2023)
1112

src/adapter/breakpoints.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import { inject, injectable } from 'inversify';
66
import Cdp from '../cdp/api';
77
import { ILogger, LogTag } from '../common/logging';
8-
import { bisectArray } from '../common/objUtils';
8+
import { bisectArray, flatten } from '../common/objUtils';
99
import { IPosition } from '../common/positions';
1010
import { delay } from '../common/promiseUtil';
1111
import { SourceMap } from '../common/sourceMaps/sourceMap';
@@ -193,7 +193,7 @@ export class BreakpointManager {
193193
}
194194
}
195195

196-
return (await Promise.all(todo)).reduce((a, b) => [...a, ...b], []);
196+
return flatten(await Promise.all(todo));
197197
};
198198
}
199199

src/adapter/threads.ts

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ export type Script = {
108108
export type ScriptWithSourceMapHandler = (
109109
script: Script,
110110
sources: Source[],
111-
brokenOn?: Cdp.Debugger.Location,
112111
) => Promise<IUiLocation[]>;
113112
export type SourceMapDisabler = (hitBreakpoints: string[]) => ISourceWithMap[];
114113

@@ -147,6 +146,13 @@ const getReplSourceSuffix = () =>
147146
sourceUtils.SourceConstants.ReplExtension
148147
}\n`;
149148

149+
/** Auxillary data present in Cdp.Debugger.Paused events in recent Chrome versions */
150+
interface IInstrumentationPauseAuxData {
151+
scriptId: string;
152+
url: string;
153+
sourceMapURL: string;
154+
}
155+
150156
export class Thread implements IVariableStoreLocationProvider {
151157
private static _lastThreadId = 0;
152158
public readonly id: number;
@@ -807,11 +813,11 @@ export class Thread implements IVariableStoreLocationProvider {
807813
// https://github.com/denoland/deno/blob/2703996dea73c496d79fcedf165886a1659622d1/core/inspector.rs#L571
808814
const isInspectBrk =
809815
(event.reason as string) === 'Break on start' || event.reason === 'debugCommand';
810-
const location = event.callFrames[0].location;
811-
const scriptId = event.data?.scriptId || location.scriptId;
816+
const location = event.callFrames[0]?.location as Cdp.Debugger.Location | undefined;
817+
const scriptId = (event.data as IInstrumentationPauseAuxData)?.scriptId || location?.scriptId;
812818
const isSourceMapPause =
813819
(event.reason === 'instrumentation' && event.data?.scriptId) ||
814-
this._breakpointManager.isEntrypointBreak(hitBreakpoints, scriptId);
820+
(scriptId && this._breakpointManager.isEntrypointBreak(hitBreakpoints, scriptId));
815821
this.evaluator.setReturnedValue(event.callFrames[0]?.returnValue);
816822

817823
if (isSourceMapPause) {
@@ -826,7 +832,7 @@ export class Thread implements IVariableStoreLocationProvider {
826832
event.data.__rewriteAs = 'breakpoint';
827833
}
828834

829-
if (await this._handleSourceMapPause(scriptId, location)) {
835+
if (scriptId && (await this._handleSourceMapPause(scriptId, location))) {
830836
// Pause if we just resolved a breakpoint that's on this
831837
// location; this won't have existed before now.
832838
} else if (isInspectBrk) {
@@ -1483,7 +1489,10 @@ export class Thread implements IVariableStoreLocationProvider {
14831489
* Wait for source map to load and set all breakpoints in this particular
14841490
* script. Returns true if the debugger should remain paused.
14851491
*/
1486-
async _handleSourceMapPause(scriptId: string, brokenOn: Cdp.Debugger.Location): Promise<boolean> {
1492+
async _handleSourceMapPause(
1493+
scriptId: string,
1494+
brokenOn?: Cdp.Debugger.Location,
1495+
): Promise<boolean> {
14871496
this._pausedForSourceMapScriptId = scriptId;
14881497
const perScriptTimeout = this._sourceContainer.sourceMapTimeouts().sourceMapMinPause;
14891498
const timeout =
@@ -1496,10 +1505,7 @@ export class Thread implements IVariableStoreLocationProvider {
14961505
}
14971506

14981507
const timer = new HrTime();
1499-
const result = await Promise.race([
1500-
this._getOrStartLoadingSourceMaps(script, brokenOn),
1501-
delay(timeout),
1502-
]);
1508+
const result = await Promise.race([this._getOrStartLoadingSourceMaps(script), delay(timeout)]);
15031509

15041510
const timeSpentWallClockInMs = timer.elapsed().ms;
15051511
const sourceMapCumulativePause =
@@ -1530,24 +1536,20 @@ export class Thread implements IVariableStoreLocationProvider {
15301536
console.assert(this._pausedForSourceMapScriptId === scriptId);
15311537
this._pausedForSourceMapScriptId = undefined;
15321538

1533-
return (
1534-
!!result &&
1535-
result
1536-
.map(base1To0)
1537-
.some(
1538-
b =>
1539-
b.lineNumber === brokenOn.lineNumber &&
1540-
(brokenOn.columnNumber === undefined || brokenOn.columnNumber === b.columnNumber),
1541-
)
1542-
);
1539+
const bLine = brokenOn?.lineNumber || 0;
1540+
const bColumn = brokenOn?.columnNumber;
1541+
1542+
return !!result
1543+
?.map(base1To0)
1544+
.some(b => b.lineNumber === bLine && (bColumn === undefined || bColumn === b.columnNumber));
15431545
}
15441546

15451547
/**
15461548
* Loads sourcemaps for the given script and invokes the handler, if we
15471549
* haven't already done so. Returns a promise that resolves with the
15481550
* handler's results.
15491551
*/
1550-
private _getOrStartLoadingSourceMaps(script: Script, brokenOn?: Cdp.Debugger.Location) {
1552+
private _getOrStartLoadingSourceMaps(script: Script) {
15511553
const existing = this._sourceMapLoads.get(script.scriptId);
15521554
if (existing) {
15531555
return existing;
@@ -1557,7 +1559,7 @@ export class Thread implements IVariableStoreLocationProvider {
15571559
.then(source => this._sourceContainer.waitForSourceMapSources(source))
15581560
.then(sources =>
15591561
sources.length && this._scriptWithSourceMapHandler
1560-
? this._scriptWithSourceMapHandler(script, sources, brokenOn)
1562+
? this._scriptWithSourceMapHandler(script, sources)
15611563
: [],
15621564
);
15631565

0 commit comments

Comments
 (0)