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