{"action":"closed","issue":{"url":"https://api.github.com/repos/rust-lang/rust/issues/22886","labels_url":"https://api.github.com/repos/rust-lang/rust/issues/22886/labels{/name}","comments_url":"https://api.github.com/repos/rust-lang/rust/issues/22886/comments","events_url":"https://api.github.com/repos/rust-lang/rust/issues/22886/events","html_url":"https://github.com/rust-lang/rust/issues/22886","id":59322592,"number":22886,"title":"Crash from iterator returning borrowed reference","user":{"login":"tov","id":732548,"avatar_url":"https://avatars.githubusercontent.com/u/732548?v=3","gravatar_id":"","url":"https://api.github.com/users/tov","html_url":"https://github.com/tov","followers_url":"https://api.github.com/users/tov/followers","following_url":"https://api.github.com/users/tov/following{/other_user}","gists_url":"https://api.github.com/users/tov/gists{/gist_id}","starred_url":"https://api.github.com/users/tov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tov/subscriptions","organizations_url":"https://api.github.com/users/tov/orgs","repos_url":"https://api.github.com/users/tov/repos","events_url":"https://api.github.com/users/tov/events{/privacy}","received_events_url":"https://api.github.com/users/tov/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rust-lang/rust/labels/A-typesystem","name":"A-typesystem","color":"d7e102"}],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":9,"created_at":"2015-02-28T03:18:27Z","updated_at":"2015-06-16T20:16:21Z","closed_at":"2015-06-16T20:16:21Z","body":"With an iterator that returns a borrowed reference to its contents, it’s possible to hold the reference longer than the reference is valid. In particular, if the iterator changes its internal state, the new state can be observed via the saved reference. Check it out:\r\n\r\n```rust\r\nfn crash_please() {\r\n    let mut iter = Newtype(Some(Box::new(0)));\r\n    let saved = iter.next().unwrap();\r\n    println!(\"{}\", saved);\r\n    iter.0 = None;\r\n    println!(\"{}\", saved);\r\n}\r\n\r\nstruct Newtype(Option<Box<usize>>);\r\n\r\nimpl<'a> Iterator for Newtype {\r\n    type Item = &'a Box<usize>;\r\n\r\n    fn next(&mut self) -> Option<&Box<usize>> {\r\n        self.0.as_ref()\r\n    }\r\n}\r\n```\r\n\r\nThis clearly shouldn’t type check, but it does, and runs, and crashes:\r\n\r\n```sh\r\n0\r\nzsh: illegal hardware instruction  target/collect_bug\r\n```\r\n\r\nWhere the type error should be, I’m not sure. It seems like it’s actually a problem with traits. If we change the above code to define `next` in a non-trait impl, then it no longer passes the borrow checker:\r\n\r\n```rust\r\nimpl<'a> Newtype {\r\n    fn next(&mut self) -> Option<&Box<usize>> {\r\n        self.0.as_ref()\r\n    }\r\n}\r\n```\r\n\r\nI originally observed this bug when testing an iterator that owns a `String`; at each iteration it modifies the string and then returns a string slice borrowed from it. My non-test code worked fine because it finished with each value from the iterator before calling `next()` again, but the test code collected the iterator into a vector. This meant that all the slices in the vector continued to point to the same buffer, even after it had been modified. So for example, if the strings written to the buffer were `\"aaa\"`, `\"bb\"`, and `\"c\"`, then in the end the vector would contain `\"cba\"`, `\"cb\"`, and `\"b\"`. Creepy.\r\n\r\n## Version\r\n\r\nI’m using 1.0.0-alpha still, because I’m teaching a class and we don’t want to follow a moving target, but I confirmed that the Feb. 26 nightly has the same bug.\r\n\r\n```\r\nrustc 1.0.0-alpha (44a287e6e 2015-01-08 17:03:40 -0800)\r\nbinary: rustc\r\ncommit-hash: 44a287e6eb22ec3c2a687fc156813577464017f7\r\ncommit-date: 2015-01-08 17:03:40 -0800\r\nhost: x86_64-apple-darwin\r\nrelease: 1.0.0-alpha\r\n```\r\n\r\n\r\n"}}