Repository navigation
Description
Affected version: confirmed on release v3.3.0, commit e06dacedc4cdea90fa1286b3965d180ab94cf251.
Summary
Interval.range(unit, amount) accepts any integer amount, including 0, without validation. Because the loop's advance step and its termination check both depend on amount, an amount of 0 produces a generator that yields the same starting value forever and never reaches its stated end. Any caller that consumes the generator without an independent bound (a plain for loop, list(...), or similar) hangs indefinitely, consuming CPU with no progress, until something external kills the process.
Details
src/pendulum/interval.py:
def range(self, unit: str, amount: int = 1) -> Iterator[_T]:
method = "add"
op = operator.le
if not self._absolute and self.invert:
method = "subtract"
op = operator.ge
start, end = self.start, self.end
i = amount
while op(start, end):
yield start
start = getattr(self.start, method)(**{unit: i})
i += amountWhen amount == 0:
istarts at0andi += amountkeeps it at0on every iteration.start = self.start.add(**{unit: i})recomputes the same value asself.startevery time, since the added quantity is always0.- The loop condition
op(start, end)(effectivelystart <= end) stays true forever, becausestartnever advances pastend.
The function is a public method on Interval/Period objects (pendulum.interval(start, end).range(unit, amount)), documented as part of the library's date-range iteration API, with no stated restriction that amount must be non-zero.
Steps To Reproduce
(available upon request)
Impact
A caller that builds a date range from a step value it does not fully control (a configuration field, a query parameter, a value derived from user input) and passes it to Interval.range() can be made to hang indefinitely on amount=0, consuming a full CPU core with no progress and no way to recover short of killing the worker from outside. This is a realistic pattern: date-range "step"/"interval" parameters are commonly user- or config-driven (reporting tools, scheduling/trading-strategy libraries that iterate a period at a configurable interval, etc). A related but distinct case, a wrong-sign amount on an interval whose direction it does not match (e.g. amount=-1 on a forward interval), does not hang but instead runs away unbounded in the opposite direction from the stated end, the same missing-validation root cause producing unbounded resource consumption rather than a hang.
Suggested fix: reject amount == 0 with a ValueError, and either require the sign of amount to match the interval's direction or normalize it automatically, with regression tests covering both the zero-step and wrong-sign-step cases.
Activity