Closed
Description
** UPDATE by @nikomatsakis **
This is almost-but-not-quite a dup of #8861, see this comment for details.
** ORIGINAL POST **
This program:
struct Foo { a: int }
impl Drop for Foo {
fn drop(&mut self) {
println!("{}", self.a);
}
}
fn main() {
{
let _1 = Foo { a: 1 };
let _2 = Foo { a: 2 };
match Foo { a: 3 } {
_ => {}
}
}
let _4 = Foo { a: 4 };
}
should output
3
2
1
4
but instead outputs
2
1
3
4
It appears that if the bare block around the first part of main
is removed, everything runs in the correct order. Moving the "3" Foo
into a variable also makes everything run in the right order.
This was originally reported to me in sfackler/rust-postgres#31 as a segfault, but it looks like that's probably just due to heap corruption from a use-after-free caused by this bug.
Update
IR:
join: ; preds = %case_body
call void @_ZN3Foo14glue_drop.146917h02f639dd107d06daE(%struct.Foo* %_2)
call void @_ZN3Foo14glue_drop.146917h02f639dd107d06daE(%struct.Foo* %_1)
call void @_ZN3Foo14glue_drop.146917h02f639dd107d06daE(%struct.Foo* %0) ; <-- 3
%7 = getelementptr inbounds %struct.Foo* %_4, i32 0, i32 1
store i8 1, i8* %7
%8 = getelementptr inbounds %struct.Foo* %_4, i32 0, i32 0
store i64 4, i64* %8
call void @_ZN3Foo14glue_drop.146917h02f639dd107d06daE(%struct.Foo* %_4)
ret void
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
flaper87 commentedon Apr 1, 2014
This sounds bad. Nominating
EDIT: Looks like something may be wrong in
rustc::middle::region::resolve_expr
forExprMatch
.flaper87 commentedon Apr 1, 2014
cc @nikomatsakis
sfackler commentedon Apr 1, 2014
This also pops up inNevermind, I forgot that thefor
loops (see the original issue on rust-postgres), so I don't believe it's an issue exclusively withExprMatch
.for
sugar wraps in a single branch match.nikomatsakis commentedon Apr 1, 2014
This is actually the expected behavior (if you fully grok the rules), but it's an interesting side-effect.
nikomatsakis commentedon Apr 1, 2014
@sfackler I'd like to know more about the details of the use-after-free.
nikomatsakis commentedon Apr 1, 2014
The reason this occurs is that:
sfackler commentedon Apr 1, 2014
@nikomatsakis In the example in sfackler/rust-postgres#31, the iterator has a reference to the statement, which in turn has a reference to the connection. The destructor for the iterator uses the connection to clean up the associated state on the server. But, since the connection has already been dropped, it ends up writing to a freed buffer, and then tries to send on a closed socket.
sfackler commentedon Apr 1, 2014
If the destructor order is working as intended, it seems like the bug may actually be in the lifetime verification infrastructure, since the lifetime of the iterator type should not be allowed to outlive the statement, and transitively the connection.
nikomatsakis commentedon Apr 1, 2014
That's what I'm trying to understand. If there is an unsound interaction here. I can imagine where something confusing might crop up, I have to read and better understand the example.
sfackler commentedon Apr 1, 2014
Here's a very simple version of the types used in that example:
19 remaining items