Skip to content

Resolve calc() division by zero to infinity instead of crashing - #2819

Merged
liZe merged 1 commit into
Kozea:mainfrom
binggao1230:calc-division-by-zero
Jul 2, 2026
Merged

liZe merged 1 commit into
Kozea:mainfrom
binggao1230:calc-division-by-zero

Conversation

@binggao1230

Copy link
Copy Markdown
Contributor

The bug

A division by zero inside a calc() expression raises ZeroDivisionError and aborts the entire render:

from weasyprint import HTML
HTML(string='<div style="width: calc(100px / 0)">x</div>').write_pdf()
# Traceback ...
#   File ".../weasyprint/css/__init__.py", line 724, in _resolve_calc_product
#     value /= calc.value
# ZeroDivisionError: division by zero

It also fires when the divisor merely evaluates to zero, e.g. calc(100px / (1 - 1)).

Why the expected behaviour is unambiguous

CSS Values and Units 4 §10.10 requires a division by zero to resolve to +∞, −∞, or NaN following IEEE-754, not to be an error: a positive numerator gives +∞, a negative one −∞, and 0 / 0 gives NaN. WeasyPrint already supports infinite and NaN values in calc() (calc(infinity * 1px), calc(nan * 1px), and the clamp() tests use calc(-infinity * 1px)), so only the division operator was missing the case.

The fix

In _resolve_calc_product, when the divisor is zero, produce ±infinity/NaN (IEEE-754) instead of dividing. The result is identical to the equivalent calc(infinity * …) / calc(nan * …) expression, which then flows through the existing infinity handling (an infinite width renders as inf, a negative-infinite/NaN width clamps to 0, exactly as the keyword forms already do).

Tests

test_calc_division_by_zero asserts the rendered width of each division-by-zero form equals that of its calc(infinity * …) / calc(nan * …) counterpart — covering positive/negative numerators, relative units, a divisor that evaluates to zero, 0 / 0 (NaN), and infinity propagating through a following +/*. All eight cases fail on main with the original ZeroDivisionError and pass with the fix; the full tests/css/test_math.py (439 passed) and test_validation.py stay green, ruff check clean.

A division by zero inside a calc() expression (e.g. width: calc(100px / 0),
or a divisor that evaluates to zero) raised ZeroDivisionError and aborted the
whole render. CSS Values and Units 4 requires such a division to resolve to
+/-infinity or NaN following IEEE-754, which WeasyPrint already supports for
calc(infinity * ...) expressions; produce those values instead of dividing.
@liZe

liZe commented Jul 2, 2026

Copy link
Copy Markdown
Member

Thanks for the fix!

@liZe
liZe merged commit f0b9bfc into Kozea:main Jul 2, 2026
@liZe liZe added this to the 70.0 milestone Jul 2, 2026
@liZe liZe added the crash Problems preventing documents from being rendered label Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

crash Problems preventing documents from being rendered

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants