summaryrefslogtreecommitdiff
path: root/crates/typst-utils/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2024-05-30 14:46:47 +0200
committerGitHub <noreply@github.com>2024-05-30 12:46:47 +0000
commit8a9c45e7d4e9f8d7e155c3a90ca07afc65e87238 (patch)
tree7cdc80d1d421b172f6c4431b3c722b71f9488ebf /crates/typst-utils/src
parentfa7fbb82749f6e8a150fb81c1cdd0efeb80aba14 (diff)
Fix race condition in interners (#4300)
Diffstat (limited to 'crates/typst-utils/src')
-rw-r--r--crates/typst-utils/src/pico.rs12
1 files changed, 8 insertions, 4 deletions
diff --git a/crates/typst-utils/src/pico.rs b/crates/typst-utils/src/pico.rs
index b58d6809..d531f14a 100644
--- a/crates/typst-utils/src/pico.rs
+++ b/crates/typst-utils/src/pico.rs
@@ -27,15 +27,19 @@ pub struct PicoStr(u32);
impl PicoStr {
/// Creates a new interned string.
pub fn new(string: &str) -> Self {
- if let Some(&id) = INTERNER.read().unwrap().to_id.get(string) {
+ // Try to find an existing entry that we can reuse.
+ //
+ // We could check with just a read lock, but if the string is not yet
+ // present, we would then need to recheck after acquiring a write lock,
+ // which is probably not worth it.
+ let mut interner = INTERNER.write().unwrap();
+ if let Some(&id) = interner.to_id.get(string) {
return id;
}
- let mut interner = INTERNER.write().unwrap();
- let num = interner.from_id.len().try_into().expect("out of string ids");
-
// Create a new entry forever by leaking the string. PicoStr is only
// used for strings that aren't created en masse, so it is okay.
+ let num = interner.from_id.len().try_into().expect("out of string ids");
let id = Self(num);
let string = Box::leak(string.to_string().into_boxed_str());
interner.to_id.insert(string, id);