Skip to content

Return None instead of crashing on invalid An+B input#72

Merged
liZe merged 1 commit into
Kozea:mainfrom
gaoflow:fix-parse-nth-invalid-crash
Jun 21, 2026
Merged

Return None instead of crashing on invalid An+B input#72
liZe merged 1 commit into
Kozea:mainfrom
gaoflow:fix-parse-nth-invalid-crash

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Steps

tinycss2.nth.parse_nth is documented to return None for invalid input, but several short, plausible truncated An+B fragments crash instead:

from tinycss2.nth import parse_nth
parse_nth("+")     # StopIteration
parse_nth("+/**/") # StopIteration
parse_nth("n+")    # AttributeError: 'NoneType' object has no attribute 'type'
parse_nth("2n +")  # AttributeError

Two unguarded token reads:

  • parse_nth (after a leading +): next(tokens) reads the next token without guarding against an exhausted iterator. The raw next is intentional — whitespace after + must stay invalid, so it can't be skipped — but exhaustion wasn't handled.
  • parse_signless_b: _next_significant(tokens) can return None, then token.type dereferences it.

Fix

Use next(tokens, None) and add token is not None guards so both paths fall through to the function's implicit return None, matching the documented contract.

Whitespace-sensitivity is preserved: +n(1, 0) (valid), + nNone (invalid), confirmed against the official An+B.json test data.

Added regression tests in tests/test_tinycss2.py; the full suite passes (16975).

Notes

Found by fuzzing the public API. This pull request was prepared with the assistance of AI, under my direction and review.

parse_nth is documented to return None for invalid input, but several
truncated nth-child fragments crashed instead:
- '+' (and '+/**/') raised StopIteration: after a leading '+', next(tokens)
  read the following token without guarding against an exhausted iterator.
- 'n+', 'n +', '-n-', '2n +' raised AttributeError: parse_signless_b
  dereferenced token.type when _next_significant returned None.

Guard both reads so they fall through to the function's implicit return None.
Whitespace after a leading '+' stays invalid ('+ n' -> None, '+n' -> (1, 0)),
matching the An+B spec test data.
@liZe

liZe commented Jun 21, 2026

Copy link
Copy Markdown
Member

Thank you!

@liZe liZe merged commit b5d95b7 into Kozea:main Jun 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants