Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fat pointers with same data part, but different vtables #48795

Closed
rom1v opened this issue Mar 6, 2018 · 6 comments
Closed

Fat pointers with same data part, but different vtables #48795

rom1v opened this issue Mar 6, 2018 · 6 comments
Labels
A-codegen Area: Code generation A-traits Area: Trait system C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@rom1v
Copy link

rom1v commented Mar 6, 2018

I did not manage to reproduce in a minimal sample, but in my application, I ended up with:

let x = …;
let y = …;
println!("{:p} == {:p} ? {}", x, y, ptr::eq(x, y));

printing:

0x7f87a8c3a618 == 0x7f87a8c3a618 ? false

After investigations (and discussion on freenode/##rust), it appeared that x and y were fat pointers having the same data part (the 64 first bits), but a different vtable (the last 64 bits).

I applied this patch to my application, which solves the reported issue: Genymobile/gnirehtet@c36fa4d

But I can't understand how two fat pointers for the same objects may have different vtables. Is it expected?

@sfackler
Copy link
Member

sfackler commented Mar 6, 2018

We don't guarantee that vtables are unique. For example, a separate copy could be generated in multiple codegen units, or multiple crates.

@Centril Centril added A-codegen Area: Code generation A-traits Area: Trait system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Mar 7, 2018
@rom1v
Copy link
Author

rom1v commented Mar 7, 2018

OK.

In that case, shouldn't ptr::eq() ignore the vtable part?

rom1v added a commit to rom1v/rust that referenced this issue Mar 7, 2018
Two fat pointers may point to the same data, but with different vtables
(the compiler do not guarantee that vtables are unique).

Such pointers should be considered equal by std::ptr::eq(), so cast them
to thin pointers to compare only their data part.

See <rust-lang#48795>.
@rom1v
Copy link
Author

rom1v commented Mar 7, 2018

This also affects slices:

use std::ptr;
fn main() {
    let array = [1, 2, 3, 4];
    let slice1 = &array[0..1];
    let slice2 = &array[0..3];
    println!("{:p} == {:p} ? {}", slice1, slice2, ptr::eq(slice1, slice2));
}
0x7fff0a6595b8 == 0x7fff0a6595b8 ? false

@hetmankp
Copy link

Here is the smallest sample I managed to find to demonstrate this on my system using rustups's 1.27.0-nightly. It appears this is only reproducible with incremental builds, which is why it won't show up when trying it with Rust Playground.

use std::path::Path;

pub trait Block { }

struct Inner {
    data: i32,
}

impl Block for Inner { }

impl Inner {
    fn new_box(data: i32) -> Box<Inner> {
        Box::new(Inner {
            data: data,
        })
    }
}

pub struct Outer {
    inner: Box<Inner>,
    block: *mut Block,
}

impl Outer {
    pub fn new_box<P: AsRef<Path>>() -> Box<Outer> {
        let mut inner = Inner::new_box(123);
        let block = &mut *inner as *mut _;

        Box::new(Outer {
            inner: inner,
            block: block,
        })
    }

    pub fn get_inner(&mut self) -> &mut Block {
        &mut *self.inner
    }
}

fn main() {
    let mut outer = Outer::new_box::<&str>();
    let b = outer.block;
    let a = outer.get_inner() as *mut Block;
    println!("{:p} == {:p}: {}", a, b, a == b);
}

Result:

$ rustc main.rs -C incremental=./inc
$ ./main
0x7f0672a23008 == 0x7f0672a23008: false

@XAMPPRocky XAMPPRocky added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label May 21, 2018
@njaard
Copy link

njaard commented Dec 27, 2018

I'm being bit by this problem also. It's causing ptr::eq to fail which is breaking my program. It seems as though you could compare the vtable itself byte-for-byte to fix the problem, as their contents are the same.

@RalfJung
Copy link
Member

RalfJung commented Mar 7, 2020

Closing as duplicate of #46139.

@RalfJung RalfJung closed this as completed Mar 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-codegen Area: Code generation A-traits Area: Trait system C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants