From 9b3c3ccc4b22f9bae07b2121cbe63dfe696784a7 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Wed, 22 Jan 2025 20:20:38 -0800 Subject: [PATCH 1/2] Desktop,Mobile: Plugins: Legacy editor API: Fix delayed crash caused by out-of-bounds inputs See #11710 --- .../CodeMirror5Emulation.test.ts | 16 ++++++++++++++++ .../CodeMirror5Emulation/CodeMirror5Emulation.ts | 8 ++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.test.ts b/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.test.ts index 229d1cdaad0..4091203a229 100644 --- a/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.test.ts +++ b/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.test.ts @@ -185,4 +185,20 @@ describe('CodeMirror5Emulation', () => { expect(lastThis).toBe(codeMirror); }); + + it('.markText should support specifying ranges outside the document', () => { + const codeMirror = makeCodeMirrorEmulation('Test...'); + + const testClassName = 'out-of-range-test-mark'; + codeMirror.markText( + // In range + { line: 0, ch: 4 }, + // Out of range + { line: 0, ch: 1002 }, + { className: testClassName }, + ); + + const dom = codeMirror.editor.dom; + expect(dom.querySelectorAll(`.${testClassName}`)).toHaveLength(1); + }); }); diff --git a/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.ts b/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.ts index 7e57e353300..56c90d620d1 100644 --- a/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.ts +++ b/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.ts @@ -37,6 +37,10 @@ interface DocumentPositionRange { to: DocumentPosition; } +const clampPositionToDoc = (doc: Text, pos: number) => { + return Math.min(Math.max(0, pos), doc.length); +}; + const documentPositionFromPos = (doc: Text, pos: number): DocumentPosition => { const line = doc.lineAt(pos); return { @@ -420,8 +424,8 @@ export default class CodeMirror5Emulation extends BaseCodeMirror5Emulation { const doc = this.editor.state.doc; return this._decorator.markText( - posFromDocumentPosition(doc, from), - posFromDocumentPosition(doc, to), + clampPositionToDoc(doc, posFromDocumentPosition(doc, from)), + clampPositionToDoc(doc, posFromDocumentPosition(doc, to)), options, ); } From cb3984bd10b3043a03cdb8eb89d12b74f4ed9766 Mon Sep 17 00:00:00 2001 From: Henry Heino Date: Wed, 22 Jan 2025 20:27:46 -0800 Subject: [PATCH 2/2] Add additional validation --- .../CodeMirror5Emulation/CodeMirror5Emulation.test.ts | 9 +++++++++ .../CodeMirror5Emulation/CodeMirror5Emulation.ts | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.test.ts b/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.test.ts index 4091203a229..0796774fc64 100644 --- a/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.test.ts +++ b/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.test.ts @@ -201,4 +201,13 @@ describe('CodeMirror5Emulation', () => { const dom = codeMirror.editor.dom; expect(dom.querySelectorAll(`.${testClassName}`)).toHaveLength(1); }); + + it('.markText should throw when given non-integer boundaries', () => { + const codeMirror = makeCodeMirrorEmulation('Test...'); + + expect(() => codeMirror.markText( + { line: 0, ch: 4.2 }, + { line: 0, ch: 5 }, + )).toThrow(/is not an integer/i); + }); }); diff --git a/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.ts b/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.ts index 56c90d620d1..16a2c8c8187 100644 --- a/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.ts +++ b/packages/editor/CodeMirror/CodeMirror5Emulation/CodeMirror5Emulation.ts @@ -52,7 +52,12 @@ const documentPositionFromPos = (doc: Text, pos: number): DocumentPosition => { const posFromDocumentPosition = (doc: Text, pos: DocumentPosition) => { const line = doc.line(pos.line + 1); - return line.from + pos.ch; + const result = line.from + pos.ch; + + if (!Number.isInteger(result)) { + throw new Error(`Document position ${result} (${pos.line}:${pos.ch}) is not an integer`); + } + return result; }; export default class CodeMirror5Emulation extends BaseCodeMirror5Emulation {