Skip to content
This repository

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

Closed
bblum opened this Issue June 27, 2012 · 7 comments

3 participants

Ben Blum Tim Chevalier Patrick Walton
Ben Blum
Collaborator
bblum commented June 27, 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.

Ben Blum
Collaborator
bblum commented June 27, 2012

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

Ben Blum
Collaborator
bblum commented June 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.)

Tim Chevalier
Collaborator

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.

Ben Blum
Collaborator
bblum commented June 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)

Tim Chevalier
Collaborator

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

Tim Chevalier catamorphism closed this issue from a commit June 28, 2012
Tim Chevalier 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
Tim Chevalier catamorphism closed this in f64c23f June 30, 2012
Patrick Walton
Owner

Awesome detective work here.

Tim Chevalier
Collaborator

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

Tim Chevalier catamorphism referenced this issue from a commit July 10, 2012
Tim Chevalier 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
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.