Open
Description
vtable addresses may differ cross codegen units. To mitigate this, it would be good to have a lint that warns against comparing wide pointers with vtables.
Original report
This is a regression from the 2/27 to 2/28 nightly.
pub trait Trait {}
impl Trait for i32 {}
pub struct Obj<'a, T: 'static + Trait> {
ptr: &'a T,
trait_ptr: *const dyn Trait,
}
impl<'a, T: Trait + 'static> Drop for Obj<'a, T> {
fn drop(&mut self) {
assert_eq!(self.trait_ptr, self.ptr as *const dyn Trait);
}
}
fn main() {
let ptr = 5;
let _name = Obj {
ptr: &ptr,
trait_ptr: &ptr,
};
}
When this program is built with rustc main.rs
, it runs without any trouble. When it's built with rustc main.rs -C incremental=
, I receive the following output:
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `0x7ffee7d23864`,
right: `0x7ffee7d23864`', main.rs:11:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
From the regression window, I suspect #67332.
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
[-]Different vtables for trait object pointers in debug builds[/-][+]Different vtables for trait object pointers in incremental builds[/+]RalfJung commentedon Mar 6, 2020
Something is odd about your example, you are asserting them to be equal and then the error is that they are equal? When I run your code on playground, it works fine on nightly.
But also, note that there is no guarantee that all vtables for the same type get the same address, or that they get different addresses. Vtable address identity is an unstable implementation detail (similar to, for example, address identity of functions, or of promoteable references). In other words, I see no bug here. Could you describe the expected behavior and how that differs from the actual behavior?
Centril commentedon Mar 6, 2020
@RalfJung From my reading of the OP, it seems like there's something particular about incremental compilation here, so maybe it's not reproducible on the playground?
RalfJung commentedon Mar 6, 2020
I guess one question is whether wide ptr equality should even compare vtables, given that they are "unstable" in a sense. I am not sure if it does, but your tests indicate they do?
FWIW, the example on playground also works on stable, and in release mode. Looks like playground cannot reproduce the problem.
RalfJung commentedon Mar 6, 2020
Ah, I missed that incremental compilation is involved. Incremental compilation having an effect on vtable identity seems odd... I am not sure if we want to consider that a bug or not.^^
RalfJung commentedon Mar 6, 2020
@jdm could you adjust your example to print not just the data address but also the vtable address? That might also explain why the output looks so strange.^^
(You seem to have already diagnosed that this is about different vtable pointers, but do not explain how you arrived at that conclusion?)
Here's a totally not supported way to do that:
jonas-schievink commentedon Mar 6, 2020
Incremental may result in different codegen unit partitioning, and each codegen unit might get its own vtable, so that part seems entirely expected to me. However the assertion failure seems to show the same address here?
RalfJung commentedon Mar 6, 2020
My guess is that the main problem @jdm has is that comparing wide pointers also compares their metadata. For trait objects, this basically means equal pointers might "randomly" not be equal any more due to vtable address differences.
So either @jdm could cast the raw ptr to a thin ptr in their codebase to avoid relying on vtable identities, or else comparing wide raw pointers could ignore metadata in general -- though I expect for slices we might want it to compare the length?
jonas-schievink commentedon Mar 6, 2020
Oh, right, the vtable pointer just isn't printed
nox commentedon Mar 6, 2020
@RalfJung Do you mean that as a temporary workaround? It is definitely a regression that this broke. How codegen units are generated shouldn't influence whether two identical trait objects are indeed identical.
41 remaining items