Skip to content

Commit 692cd75

Browse files
authored
RUST-2028 Fix Decimal128 panic when parsing strings w/o a char boundary at idx 34 (#496)
1 parent 28e3925 commit 692cd75

File tree

2 files changed

+20
-0
lines changed

2 files changed

+20
-0
lines changed

src/decimal128.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ pub enum ParseError {
333333
Overflow,
334334
Underflow,
335335
InexactRounding,
336+
Unparseable,
336337
}
337338

338339
impl fmt::Display for ParseError {
@@ -344,6 +345,7 @@ impl fmt::Display for ParseError {
344345
ParseError::Overflow => write!(f, "overflow"),
345346
ParseError::Underflow => write!(f, "underflow"),
346347
ParseError::InexactRounding => write!(f, "inexact rounding"),
348+
ParseError::Unparseable => write!(f, "unparseable"),
347349
}
348350
}
349351
}
@@ -469,6 +471,12 @@ impl std::str::FromStr for ParsedDecimal128 {
469471
}
470472

471473
fn round_decimal_str(s: &str, precision: usize) -> Result<&str, ParseError> {
474+
// TODO: In 1.80+ there's split_at_checked to make sure the split doesn't
475+
// panic if the index doesn't falls at a codepoint boundary, until then
476+
// we can check it with s.is_char_boundary(precision)
477+
if !s.is_char_boundary(precision) {
478+
return Err(ParseError::Unparseable);
479+
}
472480
let (pre, post) = s.split_at(precision);
473481
// Any nonzero trimmed digits mean it would be an imprecise round.
474482
if post.chars().any(|c| c != '0') {

src/raw/test/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,22 @@ use crate::{
1010
Binary,
1111
Bson,
1212
DateTime,
13+
Decimal128,
1314
Regex,
1415
Timestamp,
1516
};
1617

18+
#[test]
19+
fn test_decimal128_doesnt_panic_on_bad_codepoint_boundary() {
20+
use crate::decimal128::ParseError;
21+
use std::str::FromStr;
22+
// idx 34 (Coefficient::MAX_DIGITS) on this string isn't a valid codepoint boundary
23+
assert!(matches!(
24+
Decimal128::from_str("111111111111111111111111111111111❤"),
25+
Err(ParseError::Unparseable)
26+
))
27+
}
28+
1729
#[test]
1830
fn string_from_document() {
1931
let rawdoc = rawdoc! {

0 commit comments

Comments
 (0)