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

Reply via email to