Skip to content

Commit

Permalink
Fix parsing out-of-bounds nan constants (#1111)
Browse files Browse the repository at this point in the history
* Fix parsing out-of-bounds `nan` constants

Previously a float token in a wasm text file could trigger a panic if it
was out of bounds, for example `nan:0xffffffffffffffff0` (16 `f` plus
one `0`). This `.unwrap()` on a parse has been replaced with a fallible
one to propagate the error handling.

* Fix tests
  • Loading branch information
alexcrichton committed Jul 12, 2023
1 parent aa16158 commit 42f4bbf
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 9 deletions.
13 changes: 5 additions & 8 deletions crates/wast/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ pub enum Float<'a> {
/// A float `NaN` representation
Nan {
/// The specific bits to encode for this float, optionally
val: Option<u64>,
val: Option<Cow<'a, str>>,
/// Whether or not this is a negative `NaN` or not.
negative: bool,
},
Expand Down Expand Up @@ -966,13 +966,10 @@ impl Token {
} => {
let src = self.src(s);
let src = if src.starts_with("n") { src } else { &src[1..] };
let mut src = src.strip_prefix("nan:0x").unwrap();
let owned;
let mut val = Cow::Borrowed(src.strip_prefix("nan:0x").unwrap());
if has_underscores {
owned = src.replace("_", "");
src = &owned;
*val.to_mut() = val.replace("_", "");
}
let val = u64::from_str_radix(src, 16).unwrap();
Float::Nan {
val: Some(val),
negative,
Expand Down Expand Up @@ -1355,14 +1352,14 @@ mod tests {
assert_eq!(
get_float("+nan:0x1"),
Float::Nan {
val: Some(1),
val: Some("1".into()),
negative: false,
},
);
assert_eq!(
get_float("nan:0x7f_ffff"),
Float::Nan {
val: Some(0x7fffff),
val: Some("7fffff".into()),
negative: false,
},
);
Expand Down
5 changes: 4 additions & 1 deletion crates/wast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,10 @@ macro_rules! float {
Float::Nan { negative, val } => {
let exp_bits = (1 << $exp_bits) - 1;
let neg_bit = *negative as $int;
let signif = val.unwrap_or(1 << (signif_bits - 1)) as $int;
let signif = match val {
Some(val) => $int::from_str_radix(val,16).ok()?,
None => 1 << (signif_bits - 1),
};
// If the significand is zero then this is actually infinity
// so we fail to parse it.
if signif & signif_mask == 0 {
Expand Down
11 changes: 11 additions & 0 deletions tests/local/bad-nan.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(assert_malformed
(module quote "(func (result f64) (f64.const nan:0x11111111800800080))")
"constant out of range")

(assert_malformed
(module quote "(func (result f64) (f64.const nan:0xffffffffffffffff0))")
"constant out of range")

(assert_malformed
(module quote "(func (result f32) (f32.const nan:0xffffffff0))")
"constant out of range")

0 comments on commit 42f4bbf

Please sign in to comment.