From 43c3acdc4e601897893a5e24948444e2604edc54 Mon Sep 17 00:00:00 2001 From: Said Aroua Date: Sun, 25 May 2025 15:50:22 +0200 Subject: [PATCH] Add guard for potential empty labels from bibliography (#5776) --- crates/typst-library/src/foundations/label.rs | 2 ++ crates/typst-library/src/model/bibliography.rs | 9 +++++++-- crates/typst-utils/src/pico.rs | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/crates/typst-library/src/foundations/label.rs b/crates/typst-library/src/foundations/label.rs index 143da2354..94ddb9a7c 100644 --- a/crates/typst-library/src/foundations/label.rs +++ b/crates/typst-library/src/foundations/label.rs @@ -54,7 +54,9 @@ pub struct Label(PicoStr); impl Label { /// Creates a label from an interned string. + /// Callers need to ensure the given string is not empty. pub fn new(name: PicoStr) -> Self { + debug_assert!(name != PicoStr::EMPTY); Self(name) } diff --git a/crates/typst-library/src/model/bibliography.rs b/crates/typst-library/src/model/bibliography.rs index 51e3b03b0..7a0669887 100644 --- a/crates/typst-library/src/model/bibliography.rs +++ b/crates/typst-library/src/model/bibliography.rs @@ -313,12 +313,17 @@ impl Bibliography { for (source, data) in sources.0.iter().zip(data) { let library = decode_library(source, data)?; for entry in library { - match map.entry(Label::new(PicoStr::intern(entry.key()))) { + let key = entry.key(); + if key.is_empty() { + bail!("empty bibliography key found"); + } + + match map.entry(Label::new(PicoStr::intern(key))) { indexmap::map::Entry::Vacant(vacant) => { vacant.insert(entry); } indexmap::map::Entry::Occupied(_) => { - duplicates.push(entry.key().into()); + duplicates.push(key.into()); } } } diff --git a/crates/typst-utils/src/pico.rs b/crates/typst-utils/src/pico.rs index 2c80d37de..449039b4a 100644 --- a/crates/typst-utils/src/pico.rs +++ b/crates/typst-utils/src/pico.rs @@ -38,6 +38,9 @@ struct Interner { pub struct PicoStr(NonZeroU64); impl PicoStr { + /// Empty string as PicoStr + pub const EMPTY: PicoStr = PicoStr::constant(""); + /// Intern a string at runtime. pub fn intern(string: &str) -> PicoStr { // Try to use bitcode or exception representations.