Aha thanks, I am beginning to understand I think. Regarding : "The first change is just to move the `addr_of` temporary (the internal name for what Steven called `foo`) up on the stack, i.e. closer to the stack frame of `main()`, since println!() uses quite a bit of stack."
How did you work this out? Is this how programs normally work? Thanks. On Sat, Apr 19, 2014 at 10:14 AM, Björn Steinbrink <[email protected]>wrote: > On 2014.04.18 20:29:27 +0100, Artella Coding wrote: > > "There's an extra layer of indirection in that struct definition. A &'a > > fn() is a pointer to a pointer to a function. A statement like > > "self_.statefn = &finished;" expands to "let foo = finished; > self_.statefn > > = &foo". That's obviously creating a dangling pointer onto the stack > which > > is why it ends up crashing." > > Just a dangling pointer is not enough for a crash. You also need some > code to corrupt the memory it is pointing at. That's the bit that makes > such errors so much fun to debug :-) > > > I'm not sure I fully understand the above. If what you say is true, then > > why does the following code (which also uses &'a fn()) work? [using rustc > > 0.11-pre-nightly (e332287 2014-04-16 00:56:30 -0700) on ubuntu 14.04] > > Actually, that code also crashes when you compile with optimizations. > The reason why it doesn't fail without optimizations is that there is > nothing that could corrupt the stack state between storing the pointer > and reading it. > > To see this, try the following: > > 1) Move the println!() in state1() _after_ the assignment. > 2) Insert `println!("{}", Some(4));` after the first call to `it.next()` > > Doing either of these changes alone doesn't change anything, but > combined, you should see a crash. > > The first change is just to move the `addr_of` temporary (the internal > name for what Steven called `foo`) up on the stack, i.e. closer to the > stack frame of `main()`, since println!() uses quite a bit of stack. > > The second one then just creates some code that uses just enough stack > to overwrite the address that `addr_of` is stored at now. > > HTH > Björn > > > struct StateMachineIter<'a> { > > statefn: &'a fn(&mut StateMachineIter<'a>) > > } > > > > fn next(self_: &mut StateMachineIter) { > > return (*self_.statefn)(self_); > > } > > > > fn state1(self_: &mut StateMachineIter) { > > println!("state1"); > > self_.statefn = &state2; > > } > > > > fn state2(self_: &mut StateMachineIter) { > > println!("state2"); > > self_.statefn = &state3; > > } > > > > fn state3(self_: &mut StateMachineIter) { > > println!("state3"); > > self_.statefn = &finished; > > } > > > > fn finished(_: &mut StateMachineIter) { > > println!("finished"); > > } > > > > fn state_iter() -> StateMachineIter { > > StateMachineIter { statefn: &state1 } > > } > > > > > > fn main() { > > let it =& mut state_iter(); > > next(it); > > next(it); > > next(it); > > next(it); > > next(it); > > > > /* > > Prints out : > > > > state1 > > state2 > > state3 > > finished > > finished > > */ > > } >
_______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
