Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust allows unsafe stack references to be pushed into HashMap under some circumstances #10078

Closed
pythonesque opened this issue Oct 26, 2013 · 3 comments
Labels
A-lifetimes Area: lifetime related A-typesystem Area: The type system

Comments

@pythonesque
Copy link
Contributor

Not sure of the precise underlying bug, but a testcase is this:

use std::hashmap::{HashMap};

enum Entry<'self,T> {
    Ref(&'self Entry<'self,T>),
    Val(T)
}

pub struct Table<'self> {
    priv inner: HashMap<&'self str, &'self Entry<'self, int>>
}

pub trait ReferenceMap<K,V> {
    fn add<'a>(&mut self, K, V) -> bool;
}
impl<'self, K, V, T : MutableMap<K,&'self Entry<'self,V>>> ReferenceMap<K,V> for T {
    fn add<'a>(&mut self, key : K, value : V) -> bool {
        // the use of &Val(value) *should* be disallowed.
        !self.contains_key(&key) && self.insert(key, &Val(value)) // ****
    }
}

impl<'self> Table<'self> {
    pub fn new() -> Table<'self> {
        Table { inner: HashMap::new() }
    }
}

impl<'self> Table<'self> {
    pub fn add<'a>(&mut self, key : &'self str, value : int) -> bool {
        self.inner.add(key, value)
    }

    pub fn lookup(&'self self, key : &'self str) -> Option<&'self int> {
        match self.deref(key) {
            Some(&Val(ref val)) => Some(val),
            _ => None
        }
    }
    fn deref(&'self self, key : &'self str) -> Option<&'self Entry<'self, int>> {
        match self.inner.find(&key) {
            Some(entry) => {
                let mut ptr = *entry;

                loop {
                    match *ptr {
                        Ref(next) => ptr = next,
                        _ => return Some(ptr),
                    }
                }
            },
            None => None
        }
    }
}


fn main() {
    let mut t = Table::new();

    t.add("foo", 2);

    // *incorrectly* prints None
    println!("{:?}", t.lookup("foo"));

    // crashes with 'enum value matched no variant'
    // println!("{:?}", t);
}

Specifically, the line marked **** is where we see the problem manifest itself.

@huonw
Copy link
Member

huonw commented Oct 26, 2013

cc @nikomatsakis

This seems to be linked to the generic implementation of ReferenceMap, since converting the generic implementation of .add to be inline in the Table one made rustc correctly complain about mismatched lifetimes.

@nikomatsakis
Copy link
Contributor

I believe this is a dup of #5781 -- but I have not verified with 100% certainty

@pythonesque
Copy link
Contributor Author

This seems to be fixed now, at least when I updated the code to latest syntax. I'll close it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: lifetime related A-typesystem Area: The type system
Projects
None yet
Development

No branches or pull requests

3 participants