[librsvg] (#344): Don't let a viewBox with overflowing numbers pass through



commit 7b4403034e9fa52aff2ac1bc21cb3a63990cd40b
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Sep 24 09:48:27 2018 -0500

    (#344): Don't let a viewBox with overflowing numbers pass through
    
    This commit adds expect_finite_number() and finite_f32() to parsers.rs.
    
    Part of issue #344 is that we need to validate parsed numbers, as
    cssparser can give us back -inf or inf when it overflows.  These
    values ripple down the code and end up creating a NaN inside a
    cairo::Matrix, which makes it invalid.
    
    This commit introduces a CssParserExt trait to have an
    expect_finite_number() method for cssparser::Parser, and the
    corresponding, low-level finite_f32() validation function.
    
    Those functions return a Result<f32, ValueErrorKind>.  This commit
    makes the following return a ValueErrorKind for the error case as
    well:
    
    * impl Parse for f64
    * parsers::number()
    * parsers::number_optional_number()
    * parsers:;integer()
    * parsers::integer_optional_integer()
    
    This has implications in all the callers, since they used to expect a
    ParseError, but must now expect ValueErrorKind.
    
    The biggest change is in transform.rs.  For simplicity, the individual
    parsers for transform functions now have two sections:  the first
    extracts f32 from cssparser::Parser, and the second validates those
    numbers and computes the final result --- instead of doing everything
    at the same time.
    
    https://gitlab.gnome.org/GNOME/librsvg/issues/344

 rsvg_internals/src/filters/color_matrix.rs         |   4 +-
 rsvg_internals/src/filters/component_transfer.rs   |  30 +++---
 rsvg_internals/src/filters/composite.rs            |  24 ++---
 rsvg_internals/src/filters/convolve_matrix.rs      |  16 +--
 rsvg_internals/src/filters/displacement_map.rs     |   6 +-
 rsvg_internals/src/filters/gaussian_blur.rs        |   2 +-
 rsvg_internals/src/filters/light/light_source.rs   |  39 +++++---
 rsvg_internals/src/filters/light/lighting.rs       |  14 +--
 rsvg_internals/src/filters/morphology.rs           |   2 +-
 rsvg_internals/src/filters/offset.rs               |  12 +--
 rsvg_internals/src/filters/turbulence.rs           |  10 +-
 rsvg_internals/src/parsers.rs                      |  44 ++++++---
 rsvg_internals/src/shapes.rs                       |   2 +-
 rsvg_internals/src/transform.rs                    | 107 ++++++++++++++-------
 rsvg_internals/src/unitinterval.rs                 |   4 +-
 rsvg_internals/src/viewbox.rs                      |   3 +
 .../render-crash/344-too-large-viewbox.svg         |   1 +
 17 files changed, 199 insertions(+), 121 deletions(-)
---
diff --git a/rsvg_internals/src/filters/color_matrix.rs b/rsvg_internals/src/filters/color_matrix.rs
index 8da52bac..ec06e230 100644
--- a/rsvg_internals/src/filters/color_matrix.rs
+++ b/rsvg_internals/src/filters/color_matrix.rs
@@ -107,7 +107,7 @@ impl NodeTrait for ColorMatrix {
                     }
                     OperationType::Saturate => {
                         let s = parsers::number(value)
-                            .map_err(|err| NodeError::parse_error(attr, err))?;
+                            .map_err(|err| NodeError::attribute_error(attr, err))?;
                         if s < 0.0 || s > 1.0 {
                             return Err(NodeError::value_error(attr, "expected value from 0 to 1"));
                         }
@@ -123,7 +123,7 @@ impl NodeTrait for ColorMatrix {
                     }
                     OperationType::HueRotate => {
                         let degrees = parsers::number(value)
-                            .map_err(|err| NodeError::parse_error(attr, err))?;
+                            .map_err(|err| NodeError::attribute_error(attr, err))?;
 
                         let (sin, cos) = degrees.to_radians().sin_cos();
 
diff --git a/rsvg_internals/src/filters/component_transfer.rs 
b/rsvg_internals/src/filters/component_transfer.rs
index 899dadce..7dc7c10b 100644
--- a/rsvg_internals/src/filters/component_transfer.rs
+++ b/rsvg_internals/src/filters/component_transfer.rs
@@ -237,21 +237,21 @@ impl NodeTrait for FuncX {
                         )?,
                     );
                 }
-                Attribute::Slope => self
-                    .slope
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
-                Attribute::Intercept => self
-                    .intercept
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
-                Attribute::Amplitude => self
-                    .amplitude
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
-                Attribute::Exponent => self
-                    .exponent
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
-                Attribute::Offset => self
-                    .offset
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+                Attribute::Slope => self.slope.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
+                Attribute::Intercept => self.intercept.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
+                Attribute::Amplitude => self.amplitude.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
+                Attribute::Exponent => self.exponent.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
+                Attribute::Offset => self.offset.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
                 _ => (),
             }
         }
diff --git a/rsvg_internals/src/filters/composite.rs b/rsvg_internals/src/filters/composite.rs
index d8586740..c95e4edf 100644
--- a/rsvg_internals/src/filters/composite.rs
+++ b/rsvg_internals/src/filters/composite.rs
@@ -75,18 +75,18 @@ impl NodeTrait for Composite {
                     self.in2.replace(Some(Input::parse(Attribute::In2, value)?));
                 }
                 Attribute::Operator => self.operator.set(parse("operator", value, ())?),
-                Attribute::K1 => self
-                    .k1
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
-                Attribute::K2 => self
-                    .k2
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
-                Attribute::K3 => self
-                    .k3
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
-                Attribute::K4 => self
-                    .k4
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+                Attribute::K1 => self.k1.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
+                Attribute::K2 => self.k2.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
+                Attribute::K3 => self.k3.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
+                Attribute::K4 => self.k4.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
                 _ => (),
             }
         }
diff --git a/rsvg_internals/src/filters/convolve_matrix.rs b/rsvg_internals/src/filters/convolve_matrix.rs
index 186fa397..d99f13ce 100644
--- a/rsvg_internals/src/filters/convolve_matrix.rs
+++ b/rsvg_internals/src/filters/convolve_matrix.rs
@@ -68,7 +68,7 @@ impl NodeTrait for ConvolveMatrix {
             match attr {
                 Attribute::Order => self.order.set(
                     parsers::integer_optional_integer(value)
-                        .map_err(|err| NodeError::parse_error(attr, err))
+                        .map_err(|err| NodeError::attribute_error(attr, err))
                         .and_then(|(x, y)| {
                             if x > 0 && y > 0 {
                                 Ok((x as u32, y as u32))
@@ -82,7 +82,7 @@ impl NodeTrait for ConvolveMatrix {
                 ),
                 Attribute::Divisor => self.divisor.set(Some(
                     parsers::number(value)
-                        .map_err(|err| NodeError::parse_error(attr, err))
+                        .map_err(|err| NodeError::attribute_error(attr, err))
                         .and_then(|x| {
                             if x != 0.0 {
                                 Ok(x)
@@ -91,13 +91,13 @@ impl NodeTrait for ConvolveMatrix {
                             }
                         })?,
                 )),
-                Attribute::Bias => self
-                    .bias
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+                Attribute::Bias => self.bias.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
                 Attribute::EdgeMode => self.edge_mode.set(EdgeMode::parse(attr, value)?),
                 Attribute::KernelUnitLength => self.kernel_unit_length.set(Some(
                     parsers::number_optional_number(value)
-                        .map_err(|err| NodeError::parse_error(attr, err))
+                        .map_err(|err| NodeError::attribute_error(attr, err))
                         .and_then(|(x, y)| {
                             if x > 0.0 && y > 0.0 {
                                 Ok((x, y))
@@ -128,7 +128,7 @@ impl NodeTrait for ConvolveMatrix {
             match attr {
                 Attribute::TargetX => self.target_x.set(Some(
                     parsers::integer(value)
-                        .map_err(|err| NodeError::parse_error(attr, err))
+                        .map_err(|err| NodeError::attribute_error(attr, err))
                         .and_then(|x| {
                             if x >= 0 && x < self.order.get().0 as i32 {
                                 Ok(x as u32)
@@ -142,7 +142,7 @@ impl NodeTrait for ConvolveMatrix {
                 )),
                 Attribute::TargetY => self.target_y.set(Some(
                     parsers::integer(value)
-                        .map_err(|err| NodeError::parse_error(attr, err))
+                        .map_err(|err| NodeError::attribute_error(attr, err))
                         .and_then(|x| {
                             if x >= 0 && x < self.order.get().1 as i32 {
                                 Ok(x as u32)
diff --git a/rsvg_internals/src/filters/displacement_map.rs b/rsvg_internals/src/filters/displacement_map.rs
index 91e2457a..41ac3944 100644
--- a/rsvg_internals/src/filters/displacement_map.rs
+++ b/rsvg_internals/src/filters/displacement_map.rs
@@ -60,9 +60,9 @@ impl NodeTrait for DisplacementMap {
                 Attribute::In2 => {
                     self.in2.replace(Some(Input::parse(Attribute::In2, value)?));
                 }
-                Attribute::Scale => self
-                    .scale
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+                Attribute::Scale => self.scale.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
                 Attribute::XChannelSelector => self
                     .x_channel_selector
                     .set(ColorChannel::parse(attr, value)?),
diff --git a/rsvg_internals/src/filters/gaussian_blur.rs b/rsvg_internals/src/filters/gaussian_blur.rs
index 448c2553..c66e7948 100644
--- a/rsvg_internals/src/filters/gaussian_blur.rs
+++ b/rsvg_internals/src/filters/gaussian_blur.rs
@@ -55,7 +55,7 @@ impl NodeTrait for GaussianBlur {
             match attr {
                 Attribute::StdDeviation => self.std_deviation.set(
                     parsers::number_optional_number(value)
-                        .map_err(|err| NodeError::parse_error(attr, err))
+                        .map_err(|err| NodeError::attribute_error(attr, err))
                         .and_then(|(x, y)| {
                             if x >= 0.0 && y >= 0.0 {
                                 Ok((x, y))
diff --git a/rsvg_internals/src/filters/light/light_source.rs 
b/rsvg_internals/src/filters/light/light_source.rs
index f6baf80a..943d4b07 100644
--- a/rsvg_internals/src/filters/light/light_source.rs
+++ b/rsvg_internals/src/filters/light/light_source.rs
@@ -214,10 +214,12 @@ impl NodeTrait for LightSource {
                     ref elevation,
                 } => match attr {
                     Attribute::Azimuth => azimuth.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     Attribute::Elevation => elevation.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     _ => (),
                 },
@@ -227,13 +229,16 @@ impl NodeTrait for LightSource {
                     ref z,
                 } => match attr {
                     Attribute::X => x.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     Attribute::Y => y.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     Attribute::Z => z.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     _ => (),
                 },
@@ -248,28 +253,36 @@ impl NodeTrait for LightSource {
                     ref limiting_cone_angle,
                 } => match attr {
                     Attribute::X => x.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     Attribute::Y => y.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     Attribute::Z => z.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     Attribute::PointsAtX => points_at_x.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     Attribute::PointsAtY => points_at_y.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     Attribute::PointsAtZ => points_at_z.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     Attribute::SpecularExponent => specular_exponent.set(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     ),
                     Attribute::LimitingConeAngle => limiting_cone_angle.set(Some(
-                        parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?,
+                        parsers::number(value)
+                            .map_err(|err| NodeError::attribute_error(attr, err))?,
                     )),
                     _ => (),
                 },
diff --git a/rsvg_internals/src/filters/light/lighting.rs b/rsvg_internals/src/filters/light/lighting.rs
index 2afbec73..33ab1fd5 100644
--- a/rsvg_internals/src/filters/light/lighting.rs
+++ b/rsvg_internals/src/filters/light/lighting.rs
@@ -108,12 +108,12 @@ impl NodeTrait for Lighting {
 
         for (_key, attr, value) in pbag.iter() {
             match attr {
-                Attribute::SurfaceScale => self
-                    .surface_scale
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+                Attribute::SurfaceScale => self.surface_scale.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
                 Attribute::KernelUnitLength => self.kernel_unit_length.set(Some(
                     parsers::number_optional_number(value)
-                        .map_err(|err| NodeError::parse_error(attr, err))
+                        .map_err(|err| NodeError::attribute_error(attr, err))
                         .and_then(|(x, y)| {
                             if x > 0.0 && y > 0.0 {
                                 Ok((x, y))
@@ -137,7 +137,7 @@ impl NodeTrait for Lighting {
                     match attr {
                         Attribute::DiffuseConstant => diffuse_constant.set(
                             parsers::number(value)
-                                .map_err(|err| NodeError::parse_error(attr, err))
+                                .map_err(|err| NodeError::attribute_error(attr, err))
                                 .and_then(|x| {
                                     if x >= 0.0 {
                                         Ok(x)
@@ -161,7 +161,7 @@ impl NodeTrait for Lighting {
                     match attr {
                         Attribute::SpecularConstant => specular_constant.set(
                             parsers::number(value)
-                                .map_err(|err| NodeError::parse_error(attr, err))
+                                .map_err(|err| NodeError::attribute_error(attr, err))
                                 .and_then(|x| {
                                     if x >= 0.0 {
                                         Ok(x)
@@ -175,7 +175,7 @@ impl NodeTrait for Lighting {
                         ),
                         Attribute::SpecularExponent => specular_exponent.set(
                             parsers::number(value)
-                                .map_err(|err| NodeError::parse_error(attr, err))
+                                .map_err(|err| NodeError::attribute_error(attr, err))
                                 .and_then(|x| {
                                     if x >= 1.0 && x <= 128.0 {
                                         Ok(x)
diff --git a/rsvg_internals/src/filters/morphology.rs b/rsvg_internals/src/filters/morphology.rs
index 892a7ad3..60fbcef0 100644
--- a/rsvg_internals/src/filters/morphology.rs
+++ b/rsvg_internals/src/filters/morphology.rs
@@ -61,7 +61,7 @@ impl NodeTrait for Morphology {
                 Attribute::Operator => self.operator.set(Operator::parse(attr, value)?),
                 Attribute::Radius => self.radius.set(
                     parsers::number_optional_number(value)
-                        .map_err(|err| NodeError::parse_error(attr, err))
+                        .map_err(|err| NodeError::attribute_error(attr, err))
                         .and_then(|(x, y)| {
                             if x >= 0.0 && y >= 0.0 {
                                 Ok((x, y))
diff --git a/rsvg_internals/src/filters/offset.rs b/rsvg_internals/src/filters/offset.rs
index 66caff87..f9f8a524 100644
--- a/rsvg_internals/src/filters/offset.rs
+++ b/rsvg_internals/src/filters/offset.rs
@@ -45,12 +45,12 @@ impl NodeTrait for Offset {
 
         for (_key, attr, value) in pbag.iter() {
             match attr {
-                Attribute::Dx => self
-                    .dx
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
-                Attribute::Dy => self
-                    .dy
-                    .set(parsers::number(value).map_err(|err| NodeError::parse_error(attr, err))?),
+                Attribute::Dx => self.dx.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
+                Attribute::Dy => self.dy.set(
+                    parsers::number(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
                 _ => (),
             }
         }
diff --git a/rsvg_internals/src/filters/turbulence.rs b/rsvg_internals/src/filters/turbulence.rs
index 74883639..1425ed54 100644
--- a/rsvg_internals/src/filters/turbulence.rs
+++ b/rsvg_internals/src/filters/turbulence.rs
@@ -73,7 +73,7 @@ impl NodeTrait for Turbulence {
             match attr {
                 Attribute::BaseFrequency => self.base_frequency.set(
                     parsers::number_optional_number(value)
-                        .map_err(|err| NodeError::parse_error(attr, err))
+                        .map_err(|err| NodeError::attribute_error(attr, err))
                         .and_then(|(x, y)| {
                             if x >= 0.0 && y >= 0.0 {
                                 Ok((x, y))
@@ -82,9 +82,9 @@ impl NodeTrait for Turbulence {
                             }
                         })?,
                 ),
-                Attribute::NumOctaves => self
-                    .num_octaves
-                    .set(parsers::integer(value).map_err(|err| NodeError::parse_error(attr, err))?),
+                Attribute::NumOctaves => self.num_octaves.set(
+                    parsers::integer(value).map_err(|err| NodeError::attribute_error(attr, err))?,
+                ),
                 // Yes, seed needs to be parsed as a number and then truncated.
                 Attribute::Seed => self.seed.set(
                     parsers::number(value)
@@ -94,7 +94,7 @@ impl NodeTrait for Turbulence {
                                 f64::from(i32::min_value()),
                                 f64::from(i32::max_value()),
                             ) as i32
-                        }).map_err(|err| NodeError::parse_error(attr, err))?,
+                        }).map_err(|err| NodeError::attribute_error(attr, err))?,
                 ),
                 Attribute::StitchTiles => self.stitch_tiles.set(StitchTiles::parse(attr, value)?),
                 Attribute::Type => self.type_.set(NoiseType::parse(attr, value)?),
diff --git a/rsvg_internals/src/parsers.rs b/rsvg_internals/src/parsers.rs
index 03efd310..064a6c21 100644
--- a/rsvg_internals/src/parsers.rs
+++ b/rsvg_internals/src/parsers.rs
@@ -46,12 +46,32 @@ pub trait Parse: Sized {
     }
 }
 
+/// Extend `cssparser::Parser` with a `expect_finite_number` method,
+/// to avoid infinities.
+pub trait CssParserExt {
+    fn expect_finite_number(&mut self) -> Result<f32, ValueErrorKind>;
+}
+
+impl<'i, 't> CssParserExt for Parser<'i, 't> {
+    fn expect_finite_number(&mut self) -> Result<f32, ValueErrorKind> {
+        finite_f32(self.expect_number()?)
+    }
+}
+
+pub fn finite_f32(n: f32) -> Result<f32, ValueErrorKind> {
+    if n.is_finite() {
+        Ok(n)
+    } else {
+        Err(ValueErrorKind::Value("expected finite number".to_string()))
+    }
+}
+
 impl Parse for f64 {
     type Data = ();
     type Err = ValueErrorKind;
 
     fn parse(parser: &mut Parser<'_, '_>, _: ()) -> Result<f64, ValueErrorKind> {
-        Ok(f64::from(parser.expect_number().map_err(|_| {
+        Ok(f64::from(parser.expect_finite_number().map_err(|_| {
             ValueErrorKind::Parse(ParseError::new("expected number"))
         })?))
     }
@@ -161,22 +181,22 @@ pub fn optional_comma(parser: &mut Parser<'_, '_>) {
 // number
 //
 // https://www.w3.org/TR/SVG11/types.html#DataTypeNumber
-pub fn number(s: &str) -> Result<f64, ParseError> {
+pub fn number(s: &str) -> Result<f64, ValueErrorKind> {
     let mut input = ParserInput::new(s);
     let mut parser = Parser::new(&mut input);
 
-    Ok(f64::from(parser.expect_number()?))
+    Ok(f64::from(parser.expect_finite_number()?))
 }
 
 // number-optional-number
 //
 // https://www.w3.org/TR/SVG/types.html#DataTypeNumberOptionalNumber
 
-pub fn number_optional_number(s: &str) -> Result<(f64, f64), ParseError> {
+pub fn number_optional_number(s: &str) -> Result<(f64, f64), ValueErrorKind> {
     let mut input = ParserInput::new(s);
     let mut parser = Parser::new(&mut input);
 
-    let x = f64::from(parser.expect_number()?);
+    let x = f64::from(parser.expect_finite_number()?);
 
     if !parser.is_exhausted() {
         let state = parser.state();
@@ -186,7 +206,7 @@ pub fn number_optional_number(s: &str) -> Result<(f64, f64), ParseError> {
             _ => parser.reset(&state),
         };
 
-        let y = f64::from(parser.expect_number()?);
+        let y = f64::from(parser.expect_finite_number()?);
 
         parser.expect_exhausted()?;
 
@@ -199,7 +219,7 @@ pub fn number_optional_number(s: &str) -> Result<(f64, f64), ParseError> {
 // integer
 //
 // https://www.w3.org/TR/SVG11/types.html#DataTypeInteger
-pub fn integer(s: &str) -> Result<i32, ParseError> {
+pub fn integer(s: &str) -> Result<i32, ValueErrorKind> {
     let mut input = ParserInput::new(s);
     let mut parser = Parser::new(&mut input);
 
@@ -209,7 +229,7 @@ pub fn integer(s: &str) -> Result<i32, ParseError> {
 // integer-optional-integer
 //
 // Like number-optional-number but with integers.
-pub fn integer_optional_integer(s: &str) -> Result<(i32, i32), ParseError> {
+pub fn integer_optional_integer(s: &str) -> Result<(i32, i32), ValueErrorKind> {
     let mut input = ParserInput::new(s);
     let mut parser = Parser::new(&mut input);
 
@@ -267,18 +287,18 @@ pub extern "C" fn rsvg_css_parse_number_optional_number(
 // Parse a list-of-points as for polyline and polygon elements
 // https://www.w3.org/TR/SVG/shapes.html#PointsBNF
 
-pub fn list_of_points(string: &str) -> Result<Vec<(f64, f64)>, ParseError> {
+pub fn list_of_points(string: &str) -> Result<Vec<(f64, f64)>, ValueErrorKind> {
     let mut input = ParserInput::new(string);
     let mut parser = Parser::new(&mut input);
 
     let mut v = Vec::new();
 
     loop {
-        let x = f64::from(parser.expect_number()?);
+        let x = f64::from(parser.expect_finite_number()?);
 
         optional_comma(&mut parser);
 
-        let y = f64::from(parser.expect_number()?);
+        let y = f64::from(parser.expect_finite_number()?);
 
         v.push((x, y));
 
@@ -336,7 +356,7 @@ pub fn number_list(
             optional_comma(parser);
         }
 
-        v.push(f64::from(parser.expect_number().map_err(|_| {
+        v.push(f64::from(parser.expect_finite_number().map_err(|_| {
             NumberListError::Parse(ParseError::new("expected number"))
         })?));
 
diff --git a/rsvg_internals/src/shapes.rs b/rsvg_internals/src/shapes.rs
index 87e40ae8..03a626c1 100644
--- a/rsvg_internals/src/shapes.rs
+++ b/rsvg_internals/src/shapes.rs
@@ -198,7 +198,7 @@ impl NodeTrait for NodePoly {
                     }
 
                     Err(e) => {
-                        return Err(NodeError::parse_error(attr, e));
+                        return Err(NodeError::attribute_error(attr, e));
                     }
                 }
             }
diff --git a/rsvg_internals/src/transform.rs b/rsvg_internals/src/transform.rs
index 01c572a6..886dd967 100644
--- a/rsvg_internals/src/transform.rs
+++ b/rsvg_internals/src/transform.rs
@@ -6,7 +6,7 @@ use cairo::MatrixTrait;
 use cssparser::{ParseError as CssParseError, Parser, Token};
 
 use error::*;
-use parsers::{optional_comma, Parse, ParseError};
+use parsers::{finite_f32, optional_comma, Parse, ParseError};
 
 impl Parse for cairo::Matrix {
     type Data = ();
@@ -80,104 +80,145 @@ fn parse_transform_function(
 fn parse_matrix_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
     parser
         .parse_nested_block(|p| {
-            let xx = f64::from(p.expect_number()?);
+            let xx = p.expect_number()?;
             optional_comma(p);
 
-            let yx = f64::from(p.expect_number()?);
+            let yx = p.expect_number()?;
             optional_comma(p);
 
-            let xy = f64::from(p.expect_number()?);
+            let xy = p.expect_number()?;
             optional_comma(p);
 
-            let yy = f64::from(p.expect_number()?);
+            let yy = p.expect_number()?;
             optional_comma(p);
 
-            let x0 = f64::from(p.expect_number()?);
+            let x0 = p.expect_number()?;
             optional_comma(p);
 
-            let y0 = f64::from(p.expect_number()?);
+            let y0 = p.expect_number()?;
 
-            Ok(cairo::Matrix::new(xx, yx, xy, yy, x0, y0))
+            Ok((xx, yx, xy, yy, x0, y0))
         }).map_err(CssParseError::<()>::basic)
-        .map_err(ValueErrorKind::from)
+        .map_err(|e| ValueErrorKind::from(e))
+        .and_then(|(xx, yx, xy, yy, x0, y0)| {
+            let xx = f64::from(finite_f32(xx)?);
+            let yx = f64::from(finite_f32(yx)?);
+            let xy = f64::from(finite_f32(xy)?);
+            let yy = f64::from(finite_f32(yy)?);
+            let x0 = f64::from(finite_f32(x0)?);
+            let y0 = f64::from(finite_f32(y0)?);
+
+            Ok(cairo::Matrix::new(xx, yx, xy, yy, x0, y0))
+        })
 }
 
 fn parse_translate_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
     parser
         .parse_nested_block(|p| {
-            let tx = f64::from(p.expect_number()?);
+            let tx = p.expect_number()?;
 
-            let ty = f64::from(
-                p.try(|p| -> Result<f32, CssParseError<'_, ()>> {
+            let ty = p
+                .try(|p| -> Result<f32, CssParseError<'_, ()>> {
                     optional_comma(p);
                     Ok(p.expect_number()?)
-                }).unwrap_or(0.0),
-            );
+                }).unwrap_or(0.0);
 
-            Ok(cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty))
+            Ok((tx, ty))
         }).map_err(CssParseError::<()>::basic)
-        .map_err(ValueErrorKind::from)
+        .map_err(|e| ValueErrorKind::from(e))
+        .and_then(|(tx, ty)| {
+            let tx = f64::from(finite_f32(tx)?);
+            let ty = f64::from(finite_f32(ty)?);
+
+            Ok(cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty))
+        })
 }
 
 fn parse_scale_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
     parser
         .parse_nested_block(|p| {
-            let x = f64::from(p.expect_number()?);
+            let x = p.expect_number()?;
 
             let y = p
                 .try(|p| -> Result<f32, CssParseError<'_, ()>> {
                     optional_comma(p);
                     Ok(p.expect_number()?)
-                }).map(f64::from)
-                .unwrap_or(x);
+                }).unwrap_or(x);
 
-            Ok(cairo::Matrix::new(x, 0.0, 0.0, y, 0.0, 0.0))
+            Ok((x, y))
         }).map_err(CssParseError::<()>::basic)
-        .map_err(ValueErrorKind::from)
+        .map_err(|e| ValueErrorKind::from(e))
+        .and_then(|(x, y)| {
+            let x = f64::from(finite_f32(x)?);
+            let y = f64::from(finite_f32(y)?);
+
+            Ok(cairo::Matrix::new(x, 0.0, 0.0, y, 0.0, 0.0))
+        })
 }
 
 fn parse_rotate_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
     parser
         .parse_nested_block(|p| {
-            let angle = f64::from(p.expect_number()?) * PI / 180.0;
-            let (s, c) = angle.sin_cos();
+            let angle = p.expect_number()?;
 
             let (tx, ty) = p
                 .try(|p| -> Result<_, CssParseError<'_, ()>> {
                     optional_comma(p);
-                    let tx = f64::from(p.expect_number()?);
+                    let tx = p.expect_number()?;
 
                     optional_comma(p);
-                    let ty = f64::from(p.expect_number()?);
+                    let ty = p.expect_number()?;
 
                     Ok((tx, ty))
                 }).unwrap_or((0.0, 0.0));
 
+            Ok((angle, tx, ty))
+        }).map_err(CssParseError::<()>::basic)
+        .map_err(|e| ValueErrorKind::from(e))
+        .and_then(|(angle, tx, ty)| {
+            let angle = f64::from(finite_f32(angle)?);
+            let tx = f64::from(finite_f32(tx)?);
+            let ty = f64::from(finite_f32(ty)?);
+
+            let angle = angle * PI / 180.0;
+            let (s, c) = angle.sin_cos();
+
             let mut m = cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, tx, ty);
 
             m = cairo::Matrix::multiply(&cairo::Matrix::new(c, s, -s, c, 0.0, 0.0), &m);
             m = cairo::Matrix::multiply(&cairo::Matrix::new(1.0, 0.0, 0.0, 1.0, -tx, -ty), &m);
             Ok(m)
-        }).map_err(CssParseError::<()>::basic)
-        .map_err(ValueErrorKind::from)
+        })
 }
 
 fn parse_skewx_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
     parser
         .parse_nested_block(|p| {
-            let a = f64::from(p.expect_number()?) * PI / 180.0;
-            Ok(cairo::Matrix::new(1.0, 0.0, a.tan(), 1.0, 0.0, 0.0))
+            let a = p.expect_number()?;
+            Ok(a)
         }).map_err(CssParseError::<()>::basic)
-        .map_err(ValueErrorKind::from)
+        .map_err(|e| ValueErrorKind::from(e))
+        .and_then(|a| {
+            let a = f64::from(finite_f32(a)?);
+
+            let a = a * PI / 180.0;
+            Ok(cairo::Matrix::new(1.0, 0.0, a.tan(), 1.0, 0.0, 0.0))
+        })
 }
 
 fn parse_skewy_args(parser: &mut Parser<'_, '_>) -> Result<cairo::Matrix, ValueErrorKind> {
     parser
         .parse_nested_block(|p| {
-            let a = f64::from(p.expect_number()?) * PI / 180.0;
-            Ok(cairo::Matrix::new(1.0, a.tan(), 0.0, 1.0, 0.0, 0.0))
+            let a = p.expect_number()?;
+            Ok(a)
         }).map_err(CssParseError::<()>::basic)
-        .map_err(ValueErrorKind::from)
+        .map_err(|e| ValueErrorKind::from(e))
+        .and_then(|a| {
+            let a = f64::from(finite_f32(a)?);
+
+            let a = a * PI / 180.0;
+            Ok(cairo::Matrix::new(1.0, a.tan(), 0.0, 1.0, 0.0, 0.0))
+        })
 }
 
 #[cfg(test)]
diff --git a/rsvg_internals/src/unitinterval.rs b/rsvg_internals/src/unitinterval.rs
index a0ff916d..a4973044 100644
--- a/rsvg_internals/src/unitinterval.rs
+++ b/rsvg_internals/src/unitinterval.rs
@@ -1,7 +1,7 @@
 use cssparser::Parser;
 
 use error::*;
-use parsers::{Parse, ParseError};
+use parsers::{CssParserExt, Parse, ParseError};
 
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub struct UnitInterval(pub f64);
@@ -19,7 +19,7 @@ impl Parse for UnitInterval {
     fn parse(parser: &mut Parser<'_, '_>, _: ()) -> Result<UnitInterval, ValueErrorKind> {
         let x = f64::from(
             parser
-                .expect_number()
+                .expect_finite_number()
                 .map_err(|_| ValueErrorKind::Parse(ParseError::new("expected number")))?,
         );
 
diff --git a/rsvg_internals/src/viewbox.rs b/rsvg_internals/src/viewbox.rs
index cc7d7bc3..a26f8239 100644
--- a/rsvg_internals/src/viewbox.rs
+++ b/rsvg_internals/src/viewbox.rs
@@ -86,5 +86,8 @@ mod tests {
         assert!(is_parse_error(&ViewBox::parse_str(" 1 2 3 4   5", ())));
 
         assert!(is_parse_error(&ViewBox::parse_str(" 1 2 foo 3 4", ())));
+
+        // https://gitlab.gnome.org/GNOME/librsvg/issues/344
+        assert!(is_parse_error(&ViewBox::parse_str("0 0 9E80.7", ())));
     }
 }
diff --git a/tests/fixtures/render-crash/344-too-large-viewbox.svg 
b/tests/fixtures/render-crash/344-too-large-viewbox.svg
new file mode 100644
index 00000000..ff89b5a0
--- /dev/null
+++ b/tests/fixtures/render-crash/344-too-large-viewbox.svg
@@ -0,0 +1 @@
+<svg width="8" viewBox="0 0 9E80.7"></svg>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]