Opened 27 minutes ago
#37464 new Bug
StepValueValidator accepts invalid values and crashes on large numbers
| Reported by: | Akshat Gupta | Owned by: | |
|---|---|---|---|
| Component: | Forms | Version: | dev |
| Severity: | Normal | Keywords: | StepValueValidator, step_size, float, OverflowError |
| Cc: | Akshat Gupta | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
StepValueValidator uses math.remainder(). That converts values to float. Large integers and Decimals lose precision or crash.
from decimal import Decimal from django import forms forms.IntegerField(step_size=2).clean("9007199254740993") # Returns 9007199254740993. It is odd, so it should be rejected. forms.IntegerField(step_size=2).clean("9" * 400) # OverflowError: int too large to convert to float forms.DecimalField(step_size=Decimal("0.1")).clean("1e400") # ValueError: math domain error forms.DecimalField(step_size=Decimal("0.01")).clean("12345678901234567.01") # ValidationError, but the value is a valid multiple of 0.01
The first case lets an invalid value through. The next two raise an unhandled exception, so user input can cause a 500 error.
Floats are also used for the tolerance (abs_tol=1e-9). So Decimal("1.00000000005") is accepted with a step of Decimal("1e-10").
I think int and Decimal values should be checked with exact arithmetic. The float path can stay as it is. Be careful not to turn the Decimal into a huge number: Fraction(Decimal("1e50000000")) takes about a minute.
I am happy to work on a patch once this is accepted.