Skip to content

Instantly share code, notes, and snippets.

@pzread
Last active June 6, 2017 10:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pzread/8339a4b3ae23c4ae904f21cdb584334e to your computer and use it in GitHub Desktop.
Save pzread/8339a4b3ae23c4ae904f21cdb584334e to your computer and use it in GitHub Desktop.
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