mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Fix race condition in interners (#4300)
This commit is contained in:
parent
fa7fbb8274
commit
8a9c45e7d4
@ -36,17 +36,20 @@ impl FileId {
|
|||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn new(package: Option<PackageSpec>, path: VirtualPath) -> Self {
|
pub fn new(package: Option<PackageSpec>, path: VirtualPath) -> Self {
|
||||||
// Try to find an existing entry that we can reuse.
|
// Try to find an existing entry that we can reuse.
|
||||||
|
//
|
||||||
|
// We could check with just a read lock, but if the pair is not yet
|
||||||
|
// present, we would then need to recheck after acquiring a write lock,
|
||||||
|
// which is probably not worth it.
|
||||||
let pair = (package, path);
|
let pair = (package, path);
|
||||||
if let Some(&id) = INTERNER.read().unwrap().to_id.get(&pair) {
|
let mut interner = INTERNER.write().unwrap();
|
||||||
|
if let Some(&id) = interner.to_id.get(&pair) {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut interner = INTERNER.write().unwrap();
|
|
||||||
let num = interner.from_id.len().try_into().expect("out of file ids");
|
|
||||||
|
|
||||||
// Create a new entry forever by leaking the pair. We can't leak more
|
// Create a new entry forever by leaking the pair. We can't leak more
|
||||||
// than 2^16 pair (and typically will leak a lot less), so its not a
|
// than 2^16 pair (and typically will leak a lot less), so its not a
|
||||||
// big deal.
|
// big deal.
|
||||||
|
let num = interner.from_id.len().try_into().expect("out of file ids");
|
||||||
let id = FileId(num);
|
let id = FileId(num);
|
||||||
let leaked = Box::leak(Box::new(pair));
|
let leaked = Box::leak(Box::new(pair));
|
||||||
interner.to_id.insert(leaked, id);
|
interner.to_id.insert(leaked, id);
|
||||||
|
@ -27,15 +27,19 @@ pub struct PicoStr(u32);
|
|||||||
impl PicoStr {
|
impl PicoStr {
|
||||||
/// Creates a new interned string.
|
/// Creates a new interned string.
|
||||||
pub fn new(string: &str) -> Self {
|
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;
|
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
|
// 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.
|
// 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 id = Self(num);
|
||||||
let string = Box::leak(string.to_string().into_boxed_str());
|
let string = Box::leak(string.to_string().into_boxed_str());
|
||||||
interner.to_id.insert(string, id);
|
interner.to_id.insert(string, id);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user