Skip to content

Commit 7bca292

Browse files
osdnkclaude
andauthored
bibtex: don't panic on an empty @string macro (#1372)
* bibtex: don't panic on an empty @string macro `scan_a_field_token_and_eat_white` inspects `str[0]` to collapse leading whitespace at the start of a field value, where `str` is the expansion of a macro token. That expansion can be the empty string — cryptobib defines over a thousand venue name/address macros as "" (e.g. `@string{acispname = ""}`) — in which case `str` is a zero-length slice and `str[0]` is out of bounds: thread 'main' panicked at crates/engine_bibtex/src/scan.rs:663: index out of bounds: the len is 0 but the index is 0 This makes tectonic unable to compile any paper that cites cryptobib. The original WEB/C BibTeX reads `str_pool[tmp_ptr]` from a shared array here and so reads one byte past harmlessly; the Rust port returns an exact-length slice, turning the same access into a panic. The copy loop a few lines below already guards with `!str.is_empty()` — the leading-whitespace check simply didn't. Guard it the same way. An empty macro then contributes nothing to the field, matching reference bibtex/bibtex8. Adds a regression test (tests/bibtex/cites/empty_macro) whose .bbl is byte-identical to bibtex8's output. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Remove comment --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 0c006e6 commit 7bca292

6 files changed

Lines changed: 31 additions & 0 deletions

File tree

crates/engine_bibtex/src/scan.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,7 @@ fn scan_a_field_token_and_eat_white(
660660
let mut str = globals.pool.get_str(strnum);
661661

662662
if globals.buffers.offset(BufTy::Ex, 1) == 0
663+
&& !str.is_empty()
663664
&& LexClass::of(str[0]) == LexClass::Whitespace
664665
{
665666
if globals.buffers.offset(BufTy::Ex, 1) >= globals.buffers.len() {

tests/bibtex.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ fn test_single_entry() {
9696
TestCase::new(&["cites", "single_entry"]).go()
9797
}
9898

99+
#[test]
100+
fn test_empty_macro() {
101+
TestCase::new(&["cites", "empty_macro"]).go()
102+
}
103+
99104
#[test]
100105
fn test_odd_strings() {
101106
TestCase::new(&["cites", "odd_strings"])

tests/bibtex/cites/empty_macro.aux

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
\relax
2+
\citation{Empty06}
3+
\bibdata{empty_macro}
4+
\bibcite{Empty06}{1}
5+
\bibstyle{../plain}

tests/bibtex/cites/empty_macro.bbl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
\begin{thebibliography}{1}
2+
3+
\bibitem{Empty06}
4+
Nobody Jr.
5+
\newblock My article.
6+
\newblock Available online, 2006.
7+
8+
\end{thebibliography}

tests/bibtex/cites/empty_macro.bib

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@string{empty = ""}
2+
3+
@misc{ Empty06,
4+
author = "Nobody Jr",
5+
title = "My Article",
6+
howpublished = empty # "Available online",
7+
year = "2006" }

tests/bibtex/cites/empty_macro.blg

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
This is BibTeX, Version 0.99d
2+
Capacity: max_strings=35307, hash_size=35307, hash_prime=30011
3+
The top-level auxiliary file: empty_macro.aux
4+
The style file: ../plain.bst
5+
Database file #1: empty_macro.bib

0 commit comments

Comments
 (0)