On 2014.04.19 14:29:59 +0100, Artella Coding wrote: > 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.
Yeah, that's basically just how programs work when using a "classical" stack. The growth direction depends on the architecture, but the idea of moving the item closer to the caller's stack frame stays the same. Note that with the spaghetti/segmented stacks that earlier versions of rust used, you might get different results (depending on whether or not the call requires a new stack segment). Of course, it also helps to know that with today's rustc + LLVM and without optimizations, variables get allocated on the stack roughly in order of their declaration (or use in case of implicitly created temporaries). This might of course change, and then different variations of the code might fail expose or hide the error. Björn > 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
