Skip to content

fix: infinite loop when RULE_CALLABLE returns zero consumed characters#135

Open
gaoflow wants to merge 1 commit into
phfaist:mainfrom
gaoflow:fix-rule-callable-zero-consumption-infinite-loop
Open

fix: infinite loop when RULE_CALLABLE returns zero consumed characters#135
gaoflow wants to merge 1 commit into
phfaist:mainfrom
gaoflow:fix-rule-callable-zero-consumption-infinite-loop

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 24, 2026

Copy link
Copy Markdown

A RULE_CALLABLE that returns zero consumed characters causes an
infinite loop in unicode_to_latex().

Root cause: _apply_rule_callable() passes the consumed count
from the callable directly to _apply_replacement() which does
p.pos += numchars. When numchars == 0, the position never
advances, and the while p.pos < len(s) loop re-fires the same
rule on the same position endlessly.

Fix (+9 lines): Guard in _apply_rule_callable() that raises
ValueError if consumed <= 0, with a descriptive message pointing
to the offending callable and input position. Prevents the hang and
gives actionable feedback.

Reproduction:

from pylatexenc.latexencode import unicode_to_latex
unicode_to_latex('a', [([('a',)], lambda s, pos: (0, 'X'))])
# Before: hangs forever (infinite loop)
# After:  ValueError: RULE_CALLABLE for rule ... returned 0

286/286 tests pass.

This pull request was prepared with the assistance of AI, under my
direction and review.

When a RULE_CALLABLE function returns (0, replacement_string),
the _apply_rule_callable method never advances the string position,
causing an infinite loop in unicode_to_latex()'s while loop.

Add a guard that raises ValueError when consumed <= 0, with a
helpful message pointing to the offending callable.
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.

1 participant