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

Closed
bblum opened this Issue Jun 28, 2012 · 7 comments

Comments

Projects
None yet
3 participants
@bblum
Contributor

bblum commented Jun 28, 2012

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

This comment has been minimized.

Show comment
Hide comment
@bblum

bblum Jun 28, 2012

Contributor

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

Contributor

bblum commented Jun 28, 2012

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

@bblum

This comment has been minimized.

Show comment
Hide comment
@bblum

bblum Jun 28, 2012

Contributor

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.)

Contributor

bblum commented Jun 28, 2012

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.)

@ghost ghost assigned catamorphism Jun 28, 2012

@catamorphism

This comment has been minimized.

Show comment
Hide comment
@catamorphism

catamorphism Jun 28, 2012

Contributor

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.

Contributor

catamorphism commented Jun 28, 2012

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

This comment has been minimized.

Show comment
Hide comment
@bblum

bblum Jun 28, 2012

Contributor

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)

Contributor

bblum commented Jun 28, 2012

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)

bblum added a commit that referenced this issue Jun 28, 2012

@catamorphism

This comment has been minimized.

Show comment
Hide comment
@catamorphism

catamorphism Jun 30, 2012

Contributor

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

Contributor

catamorphism commented Jun 30, 2012

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

@pcwalton

This comment has been minimized.

Show comment
Hide comment
@pcwalton

pcwalton Jun 30, 2012

Contributor

Awesome detective work here.

Contributor

pcwalton commented Jun 30, 2012

Awesome detective work here.

@catamorphism

This comment has been minimized.

Show comment
Hide comment
@catamorphism

catamorphism Jul 1, 2012

Contributor

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

Contributor

catamorphism commented Jul 1, 2012

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

catamorphism added a commit that referenced this issue Jul 11, 2012

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment