Skip to content

Commit f5f8c4e

Browse files
authored
fail early when too deep in recursion (microsoft#255840)
* fail early when too deep in recursion * put info in the error stack
1 parent 5df9f83 commit f5f8c4e

File tree

2 files changed

+16
-4
lines changed

2 files changed

+16
-4
lines changed

src/vs/workbench/contrib/notebook/browser/notebookCellLayoutManager.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { DeferredPromise } from '../../../../base/common/async.js';
77
import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
8-
import { ICellViewModel, CellLayoutContext } from './notebookBrowser.js';
8+
import { ICellViewModel } from './notebookBrowser.js';
99
import { NotebookEditorWidget } from './notebookEditorWidget.js';
1010
import { INotebookCellList } from './view/notebookRenderingCommon.js';
1111
import * as DOM from '../../../../base/browser/dom.js';
@@ -14,6 +14,7 @@ import { INotebookLoggingService } from '../common/notebookLoggingService.js';
1414
export class NotebookCellLayoutManager extends Disposable {
1515
private _pendingLayouts: WeakMap<ICellViewModel, IDisposable> | null = new WeakMap<ICellViewModel, IDisposable>();
1616
private _layoutDisposables: Set<IDisposable> = new Set<IDisposable>();
17+
private readonly _layoutStack: string[] = [];
1718
private _isDisposed = false;
1819
constructor(
1920
private notebookWidget: NotebookEditorWidget,
@@ -23,8 +24,16 @@ export class NotebookCellLayoutManager extends Disposable {
2324
super();
2425
}
2526

26-
async layoutNotebookCell(cell: ICellViewModel, height: number, context?: CellLayoutContext): Promise<void> {
27-
this.loggingService.debug('cell layout', `cell:${cell.handle}, height:${height}`);
27+
private checkStackDepth() {
28+
if (this._layoutStack.length > 30) {
29+
const layoutTrace = this._layoutStack.join(' -> ');
30+
throw new Error('NotebookCellLayoutManager: layout stack is too deep: ' + layoutTrace);
31+
}
32+
}
33+
34+
async layoutNotebookCell(cell: ICellViewModel, height: number): Promise<void> {
35+
const layoutTag = `cell:${cell.handle}, height:${height}`;
36+
this.loggingService.debug('cell layout', layoutTag);
2837
const viewIndex = this._list.getViewIndex(cell);
2938
if (viewIndex === undefined) {
3039
// the cell is hidden
@@ -40,6 +49,7 @@ export class NotebookCellLayoutManager extends Disposable {
4049
const pendingLayout = this._pendingLayouts?.get(cell);
4150
this._pendingLayouts?.delete(cell);
4251

52+
this._layoutStack.push(layoutTag);
4353
try {
4454
if (this._isDisposed) {
4555
return;
@@ -59,6 +69,7 @@ export class NotebookCellLayoutManager extends Disposable {
5969
return;
6070
}
6171

72+
this.checkStackDepth();
6273

6374
if (!this.notebookWidget.hasEditorFocus()) {
6475
// Do not scroll inactive notebook
@@ -76,6 +87,7 @@ export class NotebookCellLayoutManager extends Disposable {
7687

7788
this._list.updateElementHeight2(cell, height);
7889
} finally {
90+
this._layoutStack.pop();
7991
deferred.complete(undefined);
8092
if (pendingLayout) {
8193
pendingLayout.dispose();

src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2368,7 +2368,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
23682368
//#endregion
23692369

23702370
async layoutNotebookCell(cell: ICellViewModel, height: number, context?: CellLayoutContext): Promise<void> {
2371-
return this._cellLayoutManager?.layoutNotebookCell(cell, height, context);
2371+
return this._cellLayoutManager?.layoutNotebookCell(cell, height);
23722372
}
23732373

23742374
getActiveCell() {

0 commit comments

Comments
 (0)