Skip to content

Commit

Permalink
Fix Use After Free
Browse files Browse the repository at this point in the history
The String Pool now uses just a HashSet, that stores the actual Interned
Strings. The old code also stored the str slices that we where looking
for as keys, but there were never interned properly, so they were super
likely to get freed at some point and cause a Use after Free.

Fixes #47
  • Loading branch information
CryZe committed Jul 1, 2017
1 parent 1d6c4db commit cb710d1
Showing 1 changed file with 11 additions and 6 deletions.
17 changes: 11 additions & 6 deletions src/string_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::borrow::Borrow;
use std::cell::{Cell,RefCell};
use std::cmp::max;
use std::collections::LinkedList;
use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::default::Default;
use std::ops::Deref;
use std::slice;
Expand Down Expand Up @@ -131,7 +131,7 @@ pub struct StringPool {
start: Cell<*mut u8>,
end: Cell<*const u8>,
chunks: RefCell<LinkedList<Chunk>>,
index: RefCell<HashMap<InternedString, InternedString>>,
index: RefCell<HashSet<InternedString>>,
}

static CAPACITY: usize = 10240;
Expand All @@ -147,12 +147,17 @@ impl StringPool {
}

pub fn intern<'s>(&'s self, s: &str) -> &'s str {
if s == "" { return ""; }

let search_string = InternedString::from_str(s);
if s == "" {
return "";
}

let mut index = self.index.borrow_mut();
let interned_str = *index.entry(search_string).or_insert_with(|| self.do_intern(s));
if let Some(interned) = index.get(s) {
return unsafe { mem::transmute(interned as &str) };
}

index.insert(self.do_intern(s));
let interned_str: &str = index.get(s).unwrap();

// The lifetime is really matched to us
unsafe { mem::transmute(interned_str) }
Expand Down

0 comments on commit cb710d1

Please sign in to comment.