Repository navigation
bibtex: fix text.prefix$ hang on special characters - #1405
Open
StevenLi-phoenix wants to merge 3 commits into
Open
StevenLi-phoenix wants to merge 3 commits into
StevenLi-phoenix wants to merge 3 commits into
Conversation
When text.prefix$ reached a special character such as {\"o} at brace
level 1, the loop that skips to its closing brace never advanced, so
bibtex spun forever. alpha.bst and biblatex's alphabetic style hit this
for any surname with a braced accent in its first three letters.
Advance through the special character and count it as a single text
character, as bibtex.web does. This is the same loop that tectonic-typesetting#1185 fixed in
text.length$.
Fixes tectonic-typesetting#1398.
text.length$ counted every byte after the backslash of a special
character, so it returned 8 for H{\"a}hnle where BibTeX returns 6.
bibtex.web counts an entire special character as one text character,
and text.prefix$ already does so.
This shows up in alpha.bst labels for a single author whose last name
starts with a special character: the length check that decides whether
to take three letters of the last name saw {\.I} as three characters,
so the label was {\.I} rather than {\.I}lh. Update the control_seq_alpha
expectations to the BibTeX result, which also changes the sort order.
PoolCursor::append_substr copied the bytes but did not advance the
cursor, so text.prefix$ on a string that is not a scratch string (an
entry field or a literal) returned only the closing braces it adds. In
alpha.bst this left an entry labelled from its key field, with no
author, as "99" rather than "{\"O}st99".
Advance the cursor past the copied range, as append_str does.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Created by Claude Opus-5-5: the code, tests and this description were written entirely by Claude Opus-5-5.
Fixes #1398.
What was broken
Tectonic hung at "Running BibTeX" for any entry whose alphabetic label needs
a braced special character such as
{\"o}. That covers\bibliographystyle{alpha}and biblatex
style=alphabeticwithbackend=bibtex, whenever the specialcharacter falls within the first three letters of the surname. With
alpha.bstone entry is enough to trigger it, e.g.
author = {Kurt G{\"o}del}. biblatex'slabel code calls
text.prefix$on a name only in some configurations, which isprobably why a single entry did not reproduce it in the report. Tectonic printed
nothing and never finished.
Root cause
interp_text_prefix(text.prefix$) has an inner loop that skips to the closingbrace of a special character. That loop never advanced
idx, so it spun forever.#1185 fixed the same loop in
interp_text_len(text.length$). Both loops alsocounted every byte of the special character as a text character.
bibtex.webcounts an entire special character as one text character (
incr(num_text_chars)once, after the loop).
Changes
Three commits. The second and third are independent of the hang and can be
split into separate PRs if you prefer.
idxinsidethe loop and counts the special character once.
G{\"o}delnow gives thelabel
G{\"o}d31, asbibtex.webspecifies.counting fix in
interp_text_len.text.length$onH{\"a}hnlenow returns 6(it returned 8 before). In
alpha.bstthe miscount changed labels for a singleauthor whose last name starts with a special character:
{\.I}lhanwaslabelled
{\.I}and is now{\.I}lh. This changes the existingcontrol_seq_alphaexpectations. The entry order and the warning order inthe
.blgalso change, becausealpha.bstsorts by label.this while testing.
PoolCursor::append_substrcopied the bytes but did notadvance the cursor, so
text.prefix$on a non-scratch string (an entry fieldor a literal) returned only the closing braces it adds. In
alpha.bstanentry with a
keyfield and no author got the label99instead of{\"O}st99. It has been wrong since theStringPoolcursor rewrite(2742e7a), and 0.17.0 also returns an empty string for
"Smith" #3 text.prefix$on a field. The fix advances the cursor, as
append_stralready does.Tests
tests/bibtex.rscasetest_text_prefix_special(fixturetests/bibtex/cites/text_prefix_special.*, using the existingalpha.bst) hasthree entries:
G{\"o}del,G{\"{a}}rtner(nested braces inside the specialcharacter) and an entry labelled from
key = "{\"O}sterreich".masterthe test hangs:timeout 70 cargo test --features external-harfbuzz --test bibtex test_text_prefix_specialexits 124 after printing "has been running for over 60 seconds".
idxincrement (per-byte counting kept), the labels come outas
G{\"o}31andG{\"{a}}50, and the test fails.99, and the test fails.control_seq_alpha.{bbl,blg}now expect{\.I}lh. The test fails beforecommit 2 and passes after it.
pool::tests::test_write_substr. It fails before commit 3(the string is
!instead ofHello!) and passes after it.bibtexwas available here, so I wrote the expected.bblfilesfrom
bibtex.weband cross-checked them with pybtex 0.26.1, which gives thesame labels:
G{\"o}d31,G{\"{a}}r50,{\"O}st99and{\.I}lh. A run againstreal BibTeX would still be welcome.
Commands run (macOS arm64, Rust 1.97.1):
End to end, with the reproducers from the issue:
\bibliographystyle{alpha}with a singleKurt G{\"o}delentry: Tectonic0.17.0 is still in BibTeX when killed after 120 s. The patched build finishes,
and
doc.bblhas\bibitem[G{\"o}d31]{g31}.backend=bibtex,style=alphabeticwithH{\"a}hnle,M{\"u}ller,Lov{\'a}szandG\"o\"os: Tectonic 0.17.0 is killed after 90 s. The patchedbuild finishes with
labelalphavaluesH{\"a}h10,M{\"u}l01,Lov79andG\"22. The last one is unchanged by this PR. The accent inG\"o\"osis notbraced, so
text.prefix$counts\and"as ordinary characters, asbibtex.webdoes..bstthat writestext.length$and#3 text.prefix$of eachauthorfield gives5 Smi,6 H{\"a}h,7 G{\"{a}}rand5 {\.I}lhforSmith,H{\"a}hnle,G{\"{a}}rtnerand{\.I}lhan. 0.17.0 gives lengths8, 11 and 7 for the last three, and an empty prefix for
Smith.Not addressed
The issue also asks for a diagnostic or a timeout when BibTeX does not
terminate. This PR fixes the cause of the hang only.
PoolCursor::appendwritesstrings[end]without growing the pool. If a stringends exactly at the end of the allocated pool, the next
appendpanics with"index out of bounds" (shown with a unit test that adds a 65536-byte string and
then appends one byte).
add.period$and the closing braces oftext.prefix$go through this path. The code before the
StringPoolrewrite reserved roomfirst. I left it out of this PR because it is a separate bug.