[xi-core-lib] Arithmetic overflow occurs when using APIs
Author: HeeillWangCreated Sep 22, 2023Updated Jul 27, 2024
Details
I found some overflow patterns on xi-core-lib public APIs. All of these cases triggered when external crates use API of xi-core-lib. As overflow looks quite obvious, I just list up for reproduce code for the first case. Please let me know if anyone need reproduce code for other cases.
Case-1
Thread '<unnamed>' panicked at 'attempt to subtract with overflow', xi-core-lib-0.3.0/src/selection.rs:156 /// Deletes all the regions that intersect or (if delete_adjacent = true) touch the given range.
pub fn delete_range(&mut self, start: usize, end: usize, delete_adjacent: bool) {
let mut first = self.search(start);
let mut last = self.search(end);
if first >= self.regions.len() {
return;
}
if !delete_adjacent && self.regions[first].max() == start {
first += 1;
}
if last < self.regions.len()
&& ((delete_adjacent && self.regions[last].min() <= end)
|| (!delete_adjacent && self.regions[last].min() < end))
{
last += 1;
}
remove_n_at(&mut self.regions, first, last - first); // overflow!
}reproduce with :
let mut s = Selection::new_simple(SelRegion::new(0, 0));
s.delete_range(0, 0, false);Case-2
Thread '<unnamed>' panicked at 'attempt to subtract with overflow', xi-core-lib-0.3.0/src/line_cache_shadow.rs:316 pub fn request_lines(&mut self, start: usize, end: usize) {
let mut spans: Vec<(usize, RenderTactic)> = Vec::new();
let mut i = 0;
let mut line_num = 0;
while i < self.spans.len() {
let span = &self.spans[i];
if line_num + span.0 <= start {
spans.push(*span);
line_num += span.0;
i += 1;
} else {
if line_num < start {
spans.push((start - line_num, span.1));
}
break;
}
}
spans.push((end - start, RenderTactic::Render)); //overflow!
Case-3
Thread '<unnamed>' panicked at 'attempt to add with overflow', xi-core-lib-0.3.0/src/line_cache_shadow.rs:287 pub fn create(total_height: usize, first_line: usize, height: usize) -> RenderPlan {
let mut spans = Vec::new();
let mut last = 0;
let first_line = min(first_line, total_height);
if first_line > PRESERVE_EXTENT {
last = first_line - PRESERVE_EXTENT;
spans.push((last, RenderTactic::Discard));
}
if first_line > SCROLL_SLOP {
let n = first_line - SCROLL_SLOP - last;
spans.push((n, RenderTactic::Preserve));
last += n;
}
let render_end = min(first_line + height + SCROLL_SLOP, total_height);
spans.push((render_end - last, RenderTactic::Render));
last = render_end;
let preserve_end = min(first_line + height + PRESERVE_EXTENT, total_height); // overflow!
Expected vs Actual
Overflow should be prevented with checked operations. or we may consider adding assert statement.
Source: xi-editor/xi-editor