Skip to content

Integer tokens past i32 range serialize to the saturated i32 value #441

Description

@hey-jj

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions