From 6de370cb73efb73c3536823a37c56df053e4d783 Mon Sep 17 00:00:00 2001 From: Alan Zimmerman Date: Fri, 12 Jul 2024 09:01:40 -0700 Subject: [PATCH] Protect against panics from DidChangeTextDocument Summary: These panics were generated by experimenting with emacs. Reviewed By: jcpetruzza Differential Revision: D59684333 fbshipit-source-id: d4bf59614491d04d4b5e38b03eb44ccca6dc5a84 --- crates/elp/src/document.rs | 20 ++++++++++++++++---- crates/ide_db/src/line_index.rs | 7 ++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/crates/elp/src/document.rs b/crates/elp/src/document.rs index 54338f1116..d7b126fb6f 100644 --- a/crates/elp/src/document.rs +++ b/crates/elp/src/document.rs @@ -12,7 +12,7 @@ use std::ops::Range; use elp_ide::elp_ide_db::LineIndex; use lsp_types::TextDocumentContentChangeEvent; -use crate::from_proto::text_range; +use crate::from_proto::safe_text_range; use crate::line_endings::LineEndings; pub struct Document { @@ -71,9 +71,21 @@ impl Document { line_index = LineIndex::new(&self.content); } index_valid = IndexValid::UpToLineExclusive(range.start.line); - let range = text_range(&line_index, range); - self.content - .replace_range(Range::::from(range), &change.text); + if let Some(range) = safe_text_range(&line_index, range) { + if self.content.is_char_boundary(range.start().into()) + && self.content.is_char_boundary(range.end().into()) + { + self.content + .replace_range(Range::::from(range), &change.text); + } else { + log::warn!( + "discarding invalid document change char boundary: {:?}", + &change + ); + } + } else { + log::warn!("discarding invalid document change range: {:?}", &change); + } } None => { self.content = change.text; diff --git a/crates/ide_db/src/line_index.rs b/crates/ide_db/src/line_index.rs index 8fa140b95c..233dafcae4 100644 --- a/crates/ide_db/src/line_index.rs +++ b/crates/ide_db/src/line_index.rs @@ -120,7 +120,12 @@ impl LineIndex { pub fn offset(&self, line_col: LineCol) -> TextSize { //FIXME: return Result let col = self.utf16_to_utf8_col(line_col.line, line_col.col_utf16); - self.newlines[line_col.line as usize] + col + if let Some(offset) = self.newlines.get(line_col.line as usize) { + offset + col + } else { + log::warn!("line_index.offset, limiting"); + self.newlines[self.newlines.len() - 1] + col + } } pub fn safe_offset(&self, line_col: LineCol) -> Option {