From 5bde053b0d1a1a8be9dc89fc68bc4c63404eab77 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 27 Jan 2025 16:18:39 +0200 Subject: [PATCH] Avoid panics when normalizing completion label with invalid ranges (#23712) Dev builds show panics related to completion label normalization
Panic ``` index out of bounds: the len is 103 but the index is 103 zed::reliability::init_panic_hook::{{closure}}::h78130eff43c84f6f+110375521 std::panicking::rust_panic_with_hook::hfe205f6954b2c97b+87457752 std::panicking::begin_panic_handler::{{closure}}::h6cb44b3a50f28c44+87456967 std::sys::backtrace::__rust_end_short_backtrace::hf1c1f2a92799bb0e+87449337 rust_begin_unwind+87456084 core::panicking::panic_fmt::h3d8fc78294164da7+7033011 core::panicking::panic_bounds_check::h9397cb495d89a72d+7033511 project::lsp_store::ensure_uniform_list_compatible_label::haf80316ce11edd67+72663592 project::lsp_store::populate_labels_for_completions::{{closure}}::hc93c3c540ef7d2d6+72642960 project::lsp_store::LspStore::completions::{{closure}}::{{closure}}::hb4b5432e24432ca8+72336627 async_task::raw::RawTask::run::hf444c3dc07dd583b+68504803 ::run::hbf5a316eb781a10d+50646579 gpui::platform::linux::platform::::run::hc85518d4552fc4cd+50496669 gpui::app::App::run::hca4e2eaf984ca6f6+109905269 zed::main::h849467ac1a6d32c9+110413414 std::sys::backtrace::__rust_begin_short_backtrace::h81b5ee155a7cf505+110835475 std::rt::lang_start::{{closure}}::h48a83f884cfb6865+110834761 std::rt::lang_start_internal::h5e7c81cecd7f0954+87382485 main+110425932 __libc_start_call_main+22789462491720 __libc_start_main_alias_1+22789462491915 _start+10436606 ```
This can only happen when either `label.runs` or `label.filter_range` has a range that's larger than the label text, which is an error. Instead of panicking, log such errors and fall back to last index (which is not really helpful, but still). Release Notes: - N/A --- crates/project/src/lsp_store.rs | 53 +++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index 63620ab1c9b1ea8681f4c18ba38b02c067ac6104..b7d07776e2036e02a78e88a626896723f450e77d 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -8801,16 +8801,59 @@ fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) { return; } - for (range, _) in &mut label.runs { - range.start = offset_map[range.start]; - range.end = offset_map[range.end]; + let last_index = new_idx; + let mut run_ranges_errors = Vec::new(); + label.runs.retain_mut(|(range, _)| { + match offset_map.get(range.start) { + Some(&start) => range.start = start, + None => { + run_ranges_errors.push(range.clone()); + return false; + } + } + + match offset_map.get(range.end) { + Some(&end) => range.end = end, + None => { + run_ranges_errors.push(range.clone()); + range.end = last_index; + } + } + true + }); + if !run_ranges_errors.is_empty() { + log::error!( + "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}", + label.text + ); } + let mut wrong_filter_range = None; if label.filter_range == (0..label.text.len()) { label.filter_range = 0..new_text.len(); } else { - label.filter_range.start = offset_map[label.filter_range.start]; - label.filter_range.end = offset_map[label.filter_range.end]; + let mut original_filter_range = Some(label.filter_range.clone()); + match offset_map.get(label.filter_range.start) { + Some(&start) => label.filter_range.start = start, + None => { + wrong_filter_range = original_filter_range.take(); + label.filter_range.start = last_index; + } + } + + match offset_map.get(label.filter_range.end) { + Some(&end) => label.filter_range.end = end, + None => { + wrong_filter_range = original_filter_range.take(); + label.filter_range.end = last_index; + } + } + } + if let Some(wrong_filter_range) = wrong_filter_range { + log::error!( + "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}", + label.text + ); } label.text = new_text;