Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Existentials: "x as some_iface" promotion makes polymorphic fns monomorphise wrong #2734

Closed
bblum opened this Issue · 7 comments

3 participants

@bblum

This segfaults:

iface hax { } 
impl <A> of hax for A { } 
fn perform_hax<T>(x: @T) -> hax {
    x as hax 
}
fn deadcode() {
    perform_hax(@"deadcode");
}
fn main() {
    let _ = perform_hax(@42);
}

When the destructor for _ runs at the end of main, it tries to destroy @42 as though it were an @str, causing a call to free((void*)42).

It runs without segfaulting if the call in deadcode() is commented out. That call causes perform_hax(x) to get monomorphised to promote x as hax as though x were @str. With the call gone, the first monomorphisation happens at main's call, for @int.

It runs without segfaulting if deadcode() and main() are reordered lexicographically, for the same reason as above.

It runs without segfaulting if perform_hax is manually inlined (so that there are two '... as hax').

It runs without segfaulting if "let _ =" is removed in main. Filing a separate issue for that.

@bblum

note: I believe this to be an issue in the monomorphisation implementation, rather than an inherent flaw of the type system.

@bblum

Problem seems to be more general than existentials (still to do with monomorphising). I've also run into it (i.e., presence or absence of deadcode toggles segfaults) with two other open-coded approaches to implementing similar functionality, all with @-boxes.

(edit: although note that both of those involved unsafe::transmute, and i'm not sure i could reproduce without either iface or transmute.)

@catamorphism catamorphism was assigned
@catamorphism

Backing up that this is because of monomorphizing, the following hand-monomorphized version of the code doesn't leak:

iface hax { } 
impl <A> of hax for A { } 
fn perform_hax<T>(x: @T) -> hax {
    x as hax 
}
fn perform_hax_int(x: @int) -> hax {
    x as hax 
}
fn perform_hax_str(x: @str) -> hax {
    x as hax 
}
fn deadcode() {
    perform_hax_str(@"deadcode");
}
fn main() {
    let _ = perform_hax_int(@42);
}

I have a hypothesis about what the bug is, but I'll keep digging.

@bblum

Perhaps more illuminating than your code (i.e., narrowing it down) -- if you change it to this, it still doesn't crash:

fn perform_hax_int<T>(x: @T) -> hax {
    x as hax 
}
fn perform_hax_str<T>(x: @T) -> hax {
    x as hax 
}

(and then of course if you change deadcode to call perform_hax_int, it starts crashing again)

@catamorphism

I believe this is a bug in type_use. I'll keep investigating further.

@catamorphism catamorphism closed this issue from a commit
@catamorphism catamorphism Descend into ty_boxes in type_use
type_use was failing to look into ty_boxes, which caused monomorphize
to coalesce instances that shouldn't have been coalesced (because they
should actually use different type glue)

Closes #2734
f64c23f
@pcwalton
Owner

Awesome detective work here.

@catamorphism

Good work on @bblum 's part as well for coming up with the test case!

@catamorphism catamorphism referenced this issue from a commit
@catamorphism catamorphism Test for issue 2735
This probably doesn't test the actual bug, but the fix for
issue 2734 probably camouflages the actual bug (since the
effect of the #2734 test case is now "do nothing observable"
rather than "segfault").

Closes #2735
7b4190d
@catamorphism catamorphism was unassigned by bblum
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.