-
Notifications
You must be signed in to change notification settings - Fork 745
Using this
in constructor seems to be UB
#2384
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
Comments
Hmm this is a bit tricky as bindgen would generate code like this: #[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Foo {
pub _address: u8,
}
extern "C" {
#[link_name = "\u{1}_ZN3Foo3barEv"]
pub fn Foo_bar(this: *mut Foo);
}
extern "C" {
#[link_name = "\u{1}_ZN3FooC1Ev"]
pub fn Foo_Foo(this: *mut Foo);
}
impl Foo {
#[inline]
pub unsafe fn bar(&mut self) {
Foo_bar(self)
}
#[inline]
pub unsafe fn new() -> Self {
let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
Foo_Foo(__bindgen_tmp.as_mut_ptr());
__bindgen_tmp.assume_init()
}
} Whether this code exhibits UB or not depends on whatever the That being said, the reason for both pointers being different is actually our method wrappers. I don't have your code but I suspect that this: let mut foo = ::std::mem::MaybeUninit::<Foo>::uninit();
Foo_Foo(foo.as_mut_ptr());
foo.assume_init();
Foo_bar(foo.as_mut_ptr()); should print the same value twice instead. I don't see a proper way to fix it though as this happens because once The best we could do is document this behavior as you said. Maybe even add a disclaimer saying that you shouldn't rely on the pointer location if you're using the generated constructors. |
Thanks for the quick response!
Yeah that works (and also doesn't seem to cause undefined behavior anymore when passing around
Does this mean the same problem happens when passing the Foo object around, e.g. moving it into a function argument?
Sounds good, maybe adding the workaround from above would also be useful. |
This might be a bit nitpicky but getting different addresses for both pointers is not UB in the sense that this behavior is expected from the semantic of both C and Rust IMHO. The address of a value could change anytime the value is moved.
Yes! In fact, this actually happens in C++ too, this code #include<stdio.h>
class Foo {
public:
Foo() { printf("%d\n", this);}
void bar() const { printf("%d\n", this);}
};
void aux(Foo foo) {
foo.bar();
}
int main() {
Foo foo = Foo();
aux(foo);
return 0;
} will print different values.
Yeah this is going to be one of these funny things to explain as C++ constructors are "by reference" (they receive a pointer to the value to be initialized) meanwhile Rust constructors are "by value" (they return the initialized value). |
Ah yeah that makes sense. To get pointer stability, instead of passing |
Thanks! |
Input C/C++ Header
When using this from Rust like this
Then the printf calls will print different numbers. This is probably expected behavior, but it doesn't seem to be documented (would've saved me 1 hour of debugging). For example, people may use the
this
pointer to pass the class as some listener interface to one of its fields.The text was updated successfully, but these errors were encountered: