Last active
June 6, 2017 10:23
-
-
Save pzread/8339a4b3ae23c4ae904f21cdb584334e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::mem; | |
struct Link { | |
pub value: String, | |
next: *const Link, | |
} | |
impl Link { | |
fn new(value: String, next: *const Self) -> Self { | |
Self { value, next } | |
} | |
} | |
struct Table { | |
inner: HashMap<i32, Box<Link>>, | |
head: *const Link, | |
} | |
/// Implemented a Table which can insert and search by key. And show all elements in reversed order of insertion. | |
/// The reason why it uses a single linked list to maintain and record the insertion order is because in my real case, | |
/// it also needs to support element removing operation. | |
/// The design of linked list is trying to keep the elements pointed by `next` pointers alive as long as the Table itself. | |
/// So the ownerships of all elements are held by internal `HashMap` and are dropped only(?) when the Table itself is dropped. | |
impl Table { | |
fn new() -> Self { | |
Self { inner: HashMap::new(), head: std::ptr::null() } | |
} | |
fn insert(&mut self, key: i32, value: &str) { | |
if !self.inner.contains_key(&key) { | |
let link = Box::new(Link::new(value.to_owned(), self.head)); | |
self.head = &*link; | |
self.inner.insert(key, link); | |
} | |
} | |
fn get_mut(&mut self, key: i32) -> &mut Box<Link> { | |
self.inner.get_mut(&key).unwrap() | |
} | |
fn show(&self) { | |
let mut current = self.head; | |
while !current.is_null() { | |
unsafe { | |
let reference = current.as_ref().unwrap(); | |
println!("{}", reference.value); | |
current = reference.next; | |
} | |
} | |
} | |
} | |
fn main() { | |
let mut t = Table::new(); | |
// No suprise. | |
t.insert(1, "Hello"); | |
t.insert(10, "Word"); | |
t.insert(20, "!"); | |
t.get_mut(10).value = "World".to_string(); | |
t.show(); | |
// The bug is triggered by following code. | |
{ | |
let mut mutref = t.get_mut(10); | |
let otherlink = Link::new("New World".to_string(), std::ptr::null()); | |
let oldlink = mem::replace(mutref, Box::new(otherlink)); | |
} | |
println!("{}", t.get_mut(10).value); | |
let dirtything = Box::new(vec![1u8; mem::size_of::<Link>()]); | |
t.show(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment