Skip to content

Commit af83617

Browse files
author
bors-servo
authored
Auto merge of #141 - servo:rgb-clamp, r=SimonSapin
Fix overflow in rgb() parsing. `some_f32 as i32` would warp <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-cssparser/141) <!-- Reviewable:end -->
2 parents 746a395 + 932539b commit af83617

File tree

3 files changed

+29
-23
lines changed

3 files changed

+29
-23
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22

33
name = "cssparser"
4-
version = "0.13.0"
4+
version = "0.13.1"
55
authors = [ "Simon Sapin <simon.sapin@exyr.org>" ]
66

77
description = "Rust implementation of CSS Syntax Level 3"

src/color.rs

+25-22
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
use std::cmp;
65
use std::fmt;
76
use std::f32::consts::PI;
87

@@ -31,7 +30,12 @@ impl RGBA {
3130
/// clamped to the 0.0 ... 1.0 range.
3231
#[inline]
3332
pub fn from_floats(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
34-
Self::new(clamp_f32(red), clamp_f32(green), clamp_f32(blue), clamp_f32(alpha))
33+
Self::new(
34+
clamp_unit_f32(red),
35+
clamp_unit_f32(green),
36+
clamp_unit_f32(blue),
37+
clamp_unit_f32(alpha),
38+
)
3539
}
3640

3741
/// Returns a transparent color.
@@ -99,7 +103,7 @@ impl ToCss for RGBA {
99103
{
100104
// Try first with two decimal places, then with three.
101105
let mut rounded_alpha = (self.alpha_f32() * 100.).round() / 100.;
102-
if clamp_f32(rounded_alpha) != self.alpha {
106+
if clamp_unit_f32(rounded_alpha) != self.alpha {
103107
rounded_alpha = (self.alpha_f32() * 1000.).round() / 1000.;
104108
}
105109

@@ -381,20 +385,19 @@ fn parse_color_hash(value: &str) -> Result<Color, ()> {
381385
}
382386
}
383387

384-
385-
fn clamp_i32(val: i32) -> u8 {
386-
cmp::min(cmp::max(0, val), 255) as u8
387-
}
388-
389-
fn clamp_f32(val: f32) -> u8 {
388+
fn clamp_unit_f32(val: f32) -> u8 {
390389
// Scale by 256, not 255, so that each of the 256 u8 values has an equal range
391390
// of f32 values mapping to it. Floor before clamping.
392391
//
393392
// Clamping to 256 and flooring after would let 1.0 map to 256, and
394393
// `256.0_f32 as u8` is undefined behavior:
395394
//
396395
// https://github.com/rust-lang/rust/issues/10184
397-
(val * 256.).floor().max(0.).min(255.) as u8
396+
clamp_256_f32(val * 256.)
397+
}
398+
399+
fn clamp_256_f32(val: f32) -> u8 {
400+
val.floor().max(0.).min(255.) as u8
398401
}
399402

400403
#[inline]
@@ -417,10 +420,10 @@ fn parse_color_function(name: &str, arguments: &mut Parser) -> Result<Color, ()>
417420
let token = try!(arguments.next());
418421
match token {
419422
Token::Number(NumericValue { value: v, .. }) => {
420-
clamp_f32(v)
423+
clamp_unit_f32(v)
421424
}
422425
Token::Percentage(ref v) => {
423-
clamp_f32(v.unit_value)
426+
clamp_unit_f32(v.unit_value)
424427
}
425428
_ => {
426429
return Err(())
@@ -446,23 +449,23 @@ fn parse_rgb_components_rgb(arguments: &mut Parser) -> Result<(u8, u8, u8, bool)
446449
// https://drafts.csswg.org/css-color/#rgb-functions
447450
match try!(arguments.next()) {
448451
Token::Number(NumericValue { value: v, .. }) => {
449-
red = clamp_i32(v as i32);
450-
green = clamp_i32(match try!(arguments.next()) {
452+
red = clamp_256_f32(v);
453+
green = clamp_256_f32(match try!(arguments.next()) {
451454
Token::Number(NumericValue { value: v, .. }) => v,
452455
Token::Comma => {
453456
uses_commas = true;
454457
try!(arguments.expect_number())
455458
}
456459
_ => return Err(())
457-
} as i32);
460+
});
458461
if uses_commas {
459462
try!(arguments.expect_comma());
460463
}
461-
blue = clamp_i32(try!(arguments.expect_number()) as i32);
464+
blue = clamp_256_f32(try!(arguments.expect_number()));
462465
}
463466
Token::Percentage(ref v) => {
464-
red = clamp_f32(v.unit_value);
465-
green = clamp_f32(match try!(arguments.next()) {
467+
red = clamp_unit_f32(v.unit_value);
468+
green = clamp_unit_f32(match try!(arguments.next()) {
466469
Token::Percentage(ref v) => v.unit_value,
467470
Token::Comma => {
468471
uses_commas = true;
@@ -473,7 +476,7 @@ fn parse_rgb_components_rgb(arguments: &mut Parser) -> Result<(u8, u8, u8, bool)
473476
if uses_commas {
474477
try!(arguments.expect_comma());
475478
}
476-
blue = clamp_f32(try!(arguments.expect_percentage()));
479+
blue = clamp_unit_f32(try!(arguments.expect_percentage()));
477480
}
478481
_ => return Err(())
479482
};
@@ -536,8 +539,8 @@ fn parse_rgb_components_hsl(arguments: &mut Parser) -> Result<(u8, u8, u8, bool)
536539
else { lightness + saturation - lightness * saturation };
537540
let m1 = lightness * 2. - m2;
538541
let hue_times_3 = hue * 3.;
539-
let red = clamp_f32(hue_to_rgb(m1, m2, hue_times_3 + 1.));
540-
let green = clamp_f32(hue_to_rgb(m1, m2, hue_times_3));
541-
let blue = clamp_f32(hue_to_rgb(m1, m2, hue_times_3 - 1.));
542+
let red = clamp_unit_f32(hue_to_rgb(m1, m2, hue_times_3 + 1.));
543+
let green = clamp_unit_f32(hue_to_rgb(m1, m2, hue_times_3));
544+
let blue = clamp_unit_f32(hue_to_rgb(m1, m2, hue_times_3 - 1.));
542545
return Ok((red, green, blue, uses_commas));
543546
}

src/css-parsing-tests/color3.json

+3
Original file line numberDiff line numberDiff line change
@@ -253,5 +253,8 @@
253253
"hsl(10.4719755118rad, 75%, 50%)", [32, 32, 224, 255],
254254
"hsl(2.6666666666turn, 75%, 50%)", [32, 32, 224, 255],
255255

256+
"rgb(-2147483649, 4294967298, -18446744073709551619) /* https://github.com/w3c/web-platform-tests/blob/master/2dcontext/fill-and-stroke-styles/2d.fillStyle.parse.rgb-clamp-3.html */",
257+
[0, 255, 0, 255],
258+
256259
"cmyk(0, 0, 0, 0)", null
257260
]

0 commit comments

Comments
 (0)