Fix CSS angle serialization hang on huge radian values (#31280)
### What does this PR do?
Fixes a hang (infinite loop) found by fuzzing: the CSS minifier/printer
never terminates when serializing a radian `<angle>` whose value is huge
or non-finite.
```sh
# spins forever in fmodf before this change
bun build --minify ./repro.css # repro.css: a { rotate: 1e50rad }
```
Other affected inputs: `a { ro: 1.3157e308rad }` (unknown-property token
list), `transform: rotate(3.3e33rad)`, `filter: hue-rotate(1e50rad)`,
and `rotate: calc(infinity * 1rad)`.
### Cause
`Angle::to_css` decides whether a `rad` value prints shorter as `deg` by
comparing both forms with `f32_length_with_5_digits()`
(`src/css/css_parser.rs`). That helper computes `n = (value *
100000.0).round()` and then loops `while n >= 1.0 { n % 10.0; n /= 10.0;
}`.
For radian values ≥ ~3.4e33 — or an infinity coming from `calc(infinity
* 1rad)` or from the rad→deg conversion overflowing — `value * 100000.0`
overflows `f32` to `+inf`. `inf / 10.0` is still `inf`, so the loop
never makes progress and the process spins forever inside `fmodf`.
### Fix
Bail out of `f32_length_with_5_digits` when the scaled value is not
finite, returning `usize::MAX` ("longer than any finite
representation"). The comparison in `Angle::to_css` then keeps the
authored `rad` unit, and serialization proceeds through the existing
path that already clamps infinities to `3.40282e38` (same as huge `deg`
values, e.g. `rotate: 1e50deg` → `rotate:3.40282e38deg`).
Output after the fix:
| input | output |
| --- | --- |
| `rotate: 1e50rad` | `rotate:3.40282e38rad` |
| `ro: 1.3157e308rad` | `ro:3.40282e38rad` |
| `transform: rotate(3.3e33rad)` | `transform:rotate(3.3e+33rad)` |
| `filter: hue-rotate(1e50rad)` | `filter:hue-rotate(3.40282e38rad)` |
| `rotate: calc(infinity * 1rad)` | `rotate:3.40282e38rad` |
| `transform: rotate(0.017453293rad)` | `transform:rotate(1deg)`
(unchanged) |
### How did you verify your code works?
- New test `test/js/bun/css/angle-serialization-hang.test.ts` minifies
the fuzzer repros plus the other affected paths in a child process with
a kill switch. It fails (child killed / test timeout) on bun without the
fix and passes with it.
- Existing CSS suites (`css.test.ts`, `color.test.ts`,
`nested-function-backtracking.test.ts`, `doesnt_crash.test.ts`) pass
with the change: 2036 pass; the only failure is the pre-existing `fuzz
ansi256` slowness in debug builds, which is unrelated to this change.
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> R
robobun committed
14b398c802b1242bce92e7aec9f48fb0c2897b1e
Parent: 0179127
Committed by GitHub <noreply@github.com>
on 5/24/2026, 2:00:08 AM