mozilla/rust — Issue #1910: iface methods with generic ret types that get bound to unit ret to undef memory
Author: nikomatsakis
Created: 2012-02-29 05:39:55+00:00
State: open

In this test case:

```
enum deser = uint;

iface reader {
fn read_vec_elt(f: fn() -> T) -> T;
}

impl of reader for deser {
fn read_vec_elt(f: fn() -> T) -> T {
f()
}
}

fn read_to_vec(self: D, f: fn() -> T) -> [T] {
let v = [];
self.read_vec_elt() {|| v += [f()] }
v
}

fn main() {
let x = deser(1u);
assert [22u] == read_to_vec(x) {|| 22u };
}
```

The call to `self.read_vec_elt()` which occurs in `read_to_vec()` gets compiled down to some LLVM code like:

```
invoke void %40([1 x i8*]* %3, i1* undef, { i64, %tydesc*, i8*, i8*, i8 }* %41, %tydesc* @tydesc1, { void (i1*, { i64, %tydesc*, i8*, i8*, i8 }*)*, { i64, %tydesc*, i8*, i8*, i8 }* }* %8)
to label %54 unwind label %55
```

In particular, the second argument to this call (in this case, that is the destination ptr) is `i1* undef`. As a result, the return value of `()` gets written into random memory. This leads to crashes on some systems, in particular Ubuntu. This same bug is causing `block-arg.rs` to fail under testing (though not on the bots nor on macs etc).

This problem only seems to occur if the call is to an iface method. If you change the type of `self` to be `deser` or some other concrete type, the problem goes away. I presume this is some sort of interaction between the typing of iface methods vs those of other callees, because right now the code tries to get smart and avoid allocating space for the return value if the return type is unit... but in this case, that logic is not working.