From bbd5268e71de2a7718e24564f6a867e9743bd96e Mon Sep 17 00:00:00 2001 From: Mees Delzenne Date: Fri, 16 Feb 2024 18:05:24 +0100 Subject: [PATCH] Bugfix: fix a panic in span rendering (#3527) --- core/src/sql/v1/value/value.rs | 12 ++++++---- core/src/syn/common.rs | 43 ++++++++++++++++++++++++++-------- core/src/syn/mod.rs | 14 +++++++++++ 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/core/src/sql/v1/value/value.rs b/core/src/sql/v1/value/value.rs index 26227466..29b2e867 100644 --- a/core/src/sql/v1/value/value.rs +++ b/core/src/sql/v1/value/value.rs @@ -2848,16 +2848,20 @@ mod tests { #[test] fn check_size() { - assert!(64 <= std::mem::size_of::()); - assert_eq!(104, std::mem::size_of::()); - assert_eq!(104, std::mem::size_of::>()); + assert!( + 64 >= std::mem::size_of::(), + "expected Value to be smaller then 64 bytes found {:?}", + std::mem::size_of::() + ); + assert!(112 >= std::mem::size_of::()); + assert!(112 >= std::mem::size_of::>()); assert_eq!(24, std::mem::size_of::()); assert_eq!(24, std::mem::size_of::()); assert_eq!(16, std::mem::size_of::()); assert_eq!(12, std::mem::size_of::()); assert_eq!(24, std::mem::size_of::()); assert_eq!(24, std::mem::size_of::()); - assert_eq!(56, std::mem::size_of::()); + assert!(56 >= std::mem::size_of::()); assert_eq!(24, std::mem::size_of::()); assert_eq!(24, std::mem::size_of::()); assert_eq!(24, std::mem::size_of::()); diff --git a/core/src/syn/common.rs b/core/src/syn/common.rs index 917b1931..e25e79b0 100644 --- a/core/src/syn/common.rs +++ b/core/src/syn/common.rs @@ -22,14 +22,21 @@ impl Location { let offset = (substr.as_ptr() as usize) .checked_sub(input.as_ptr() as usize) .expect("tried to find location of substring in unrelated string"); - // Bytes of input prior to line being iteratated. + assert!(offset <= input.len(), "tried to find location of substring in unrelated string"); + // Bytes of input prior to line being iterated. let mut bytes_prior = 0; - for (line_idx, (line, seperator_offset)) in LineIterator::new(input).enumerate() { - let bytes_so_far = bytes_prior + line.len() + seperator_offset.unwrap_or(0) as usize; + for (line_idx, (line, seperator_len)) in LineIterator::new(input).enumerate() { + let bytes_so_far = bytes_prior + line.len() + seperator_len.unwrap_or(0) as usize; if bytes_so_far >= offset { // found line. let line_offset = offset - bytes_prior; - let column = line[..line_offset].chars().count(); + + let column = if line_offset > line.len() { + // error is inside line terminator. + line.chars().count() + 1 + } else { + line[..line_offset].chars().count() + }; // +1 because line and column are 1 index. return Self { line: line_idx + 1, @@ -43,14 +50,21 @@ impl Location { #[cfg(feature = "experimental-parser")] pub fn of_offset(source: &str, offset: usize) -> Self { - // Bytes of input prior to line being iteratated. + assert!(offset <= source.len(), "tried to find location of substring in unrelated string"); + // Bytes of input prior to line being iterated. let mut bytes_prior = 0; - for (line_idx, (line, seperator_offset)) in LineIterator::new(source).enumerate() { - let bytes_so_far = bytes_prior + line.len() + seperator_offset.unwrap_or(0) as usize; + for (line_idx, (line, seperator_len)) in LineIterator::new(source).enumerate() { + let bytes_so_far = bytes_prior + line.len() + seperator_len.unwrap_or(0) as usize; if bytes_so_far >= offset { // found line. let line_offset = offset - bytes_prior; - let column = line[..line_offset].chars().count(); + + let column = if line_offset > line.len() { + // error is inside line terminator. + line.chars().count() + 1 + } else { + line[..line_offset].chars().count() + }; // +1 because line and column are 1 index. return Self { line: line_idx + 1, @@ -94,7 +108,11 @@ impl Location { if bytes_so_far >= offset { // found line. let line_offset = offset - bytes_prior; - let column = line[..line_offset].chars().count(); + let column = if line_offset > line.len() { + line.chars().count() + 1 + } else { + line[..line_offset.min(line.len())].chars().count() + }; // +1 because line and column are 1 index. if bytes_so_far >= end { // end is on the same line, finish immediatly. @@ -124,12 +142,17 @@ impl Location { let bytes_so_far = bytes_prior + line.len() + seperator_offset.unwrap_or(0) as usize; if bytes_so_far >= end { let line_offset = end - bytes_prior; - let column = line[..line_offset].chars().count(); + let column = if line_offset > line.len() { + line.chars().count() + 1 + } else { + line[..line_offset.min(line.len())].chars().count() + }; return start..Self { line: line_idx + 1, column: column + 1, }; } + bytes_prior = bytes_so_far; } } } diff --git a/core/src/syn/mod.rs b/core/src/syn/mod.rs index e75612ed..57f5585d 100644 --- a/core/src/syn/mod.rs +++ b/core/src/syn/mod.rs @@ -20,3 +20,17 @@ pub use v2::{ pub trait Parse { fn parse(val: &str) -> T; } + +#[cfg(test)] +mod test { + use super::parse; + + #[test] + fn test_error_in_lineterminator() { + let q = r#" +select * from person +CREATE person CONTENT { foo:'bar'}; +"#; + parse(q).unwrap_err(); + } +}