consume_numeric stores an integer token's int_value by clamping to i32::MAX or i32::MIN when the parsed value falls outside i32 range (src/tokenizer.rs lines 1084 to 1094). The full magnitude survives in the f32 value field, but write_numeric prints int_value verbatim whenever it is Some and ignores value (src/serializer.rs lines 45 to 47). An integer literal larger than i32::MAX therefore serializes as 2147483647, a different number from the one that was parsed.
Version 0.37.0, default features.
Observed
Parse a number token, serialize it with ToCss, and the digits change:
input= 5000000000 serialized=2147483647
input= 4294967296 serialized=2147483647
input= 2200000000 serialized=2147483647
input= -3000000001 serialized=-2147483648
Expected
Serialization should reproduce the token's numeric value, so parse then serialize then reparse yields the same number. The CSS syntax has no upper bound on integer digit count, so a value beyond i32 range still needs to round-trip.
Reproducer
cargo add cssparser (0.37.0), then:
use cssparser::{Parser, ParserInput, ToCss};
fn serialize(s: &str) -> String {
let mut input = ParserInput::new(s);
let mut p = Parser::new(&mut input);
p.next().unwrap().to_css_string()
}
fn main() {
for s in ["5000000000", "4294967296", "2200000000", "-3000000001"] {
let out = serialize(s);
println!("input={:>12} serialized={:>12} same={}", s, out, s == out);
}
}
Every line prints same=false, and reparsing the serialized text yields the clamped value in place of the original.
Scope
A tokenize then re-emit pass, which is common in minifiers, formatters, and sanitizers built on this crate, rewrites any large integer to a bounded one with no error surfaced. Grid line indices, z-index values, animation counts, and custom numeric properties change meaning across the round trip. The clamp also applies to a Token::Dimension and a Token::Percentage, whose int_value runs through the same write_numeric path.
consume_numericstores an integer token'sint_valueby clamping toi32::MAXori32::MINwhen the parsed value falls outsidei32range (src/tokenizer.rs lines 1084 to 1094). The full magnitude survives in thef32valuefield, butwrite_numericprintsint_valueverbatim whenever it isSomeand ignoresvalue(src/serializer.rs lines 45 to 47). An integer literal larger thani32::MAXtherefore serializes as2147483647, a different number from the one that was parsed.Version 0.37.0, default features.
Observed
Parse a number token, serialize it with
ToCss, and the digits change:Expected
Serialization should reproduce the token's numeric value, so parse then serialize then reparse yields the same number. The CSS syntax has no upper bound on integer digit count, so a value beyond
i32range still needs to round-trip.Reproducer
cargo add cssparser(0.37.0), then:Every line prints
same=false, and reparsing the serialized text yields the clamped value in place of the original.Scope
A tokenize then re-emit pass, which is common in minifiers, formatters, and sanitizers built on this crate, rewrites any large integer to a bounded one with no error surfaced. Grid line indices, z-index values, animation counts, and custom numeric properties change meaning across the round trip. The clamp also applies to a
Token::Dimensionand aToken::Percentage, whoseint_valueruns through the samewrite_numericpath.