You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
as_ptr() returns a *mut _ pointer. This isn't an error by itself, but under Rust's memory model, this pointer is derived from shared/immutable &self, and therefore doesn't have permission to mutate self, so the mut of the pointer is misleading.
I assume this is for convenience, because C APIs aren't diligent about const vs mut distinction. However, this is a gotcha, because C APIs that take *mut may actually mutate the object, and that is UB from Rust's perspective.
Could you add .as_mut_ptr() that takes &mut self to provide a pointer safe for mutation?
Even for C APIs that are const-correct, C's notion of constness is distinct enough from Rust's that & <-> *const and &mut <-> *mut doesn't really work.
I've developed a version of Miri that can execute foreign functions by interpreting LLVM bytecode, and it found a Tree Borrows violation related to mutating through self.as_ptr(). Writing through the mutable pointer created from self.as_ptr() is considered undefined behavior under this model, since this pointer is given a Frozen access tag as a child tag of the implicit &self parameter to as_ptr.
Here's a minimal example that can recreate the error with an unmodified version of Miri, without the FFI. In particular, this error is triggered when mutating through self.as_ptr() within a method that receives &mut self, where self is an instance of ForeignTypeRef.
Also, I was a bit unsure about what you meant here:
C's notion of constness is distinct enough from Rust's that & <-> *const and &mut <-> *mut doesn't really work.
Are you saying that the compiler's treatment of &T differs enough from * const in C (even under a const-correct API) that this borrowing violation isn't actually problematic in practice?
Could it be because UnsafeCell in PhantomData has zero size, and doesn't exist in memory? If it was Opaque(UnsafeCell<ActualForeignSizedType>) then it would map to an address space.
Yeah, I think there's a difference between PhantomData<UnsafeCell<*mut ()>> and UnsafeCell<PhantomData<*mut ()>>, with only the latter registering as using interior mutability
I'll note again: rustccurrently treats UnsafeCell differently whether it's inside PhantomData or not! See this playground, click "Show LLVM IR", and inspect the result; the function taking &PhantomData<UnsafeCell<*mut ()>> gets marked with noalias readonly, while &UnsafeCell<PhantomData<*mut ()>> gets marked with readnone.
If you add extern types to the mix, you'll see the exact same LLVM IR as for &UnsafeCell<PhantomData<*mut ()>> (LLVM will even merge the functions because of that).
@madsmtm I think you accidentally used the same link twice.
Based on this pull request, allowing PhantomData to apply interior mutability would be a breaking change, so it's not likely to be resolved in this direction soon. It seems like it would be worthwhile to change Opaque for now until the semantics are settled.
Activity
sfackler commentedon Nov 28, 2023
The structure of
Opaqueis designed to prevent mutation through the*mutfrom being UB:foreign-types/foreign-types-shared/src/lib.rs
Line 14 in 393f6ab
Even for C APIs that are const-correct, C's notion of constness is distinct enough from Rust's that
& <-> *constand&mut <-> *mutdoesn't really work.Ensure mutable pointers are correctly derived
icmccorm commentedon Nov 30, 2023
I've developed a version of Miri that can execute foreign functions by interpreting LLVM bytecode, and it found a Tree Borrows violation related to mutating through
self.as_ptr(). Writing through the mutable pointer created fromself.as_ptr()is considered undefined behavior under this model, since this pointer is given aFrozenaccess tag as a child tag of the implicit&selfparameter toas_ptr.Here's a minimal example that can recreate the error with an unmodified version of Miri, without the FFI. In particular, this error is triggered when mutating through
self.as_ptr()within a method that receives&mut self, whereselfis an instance ofForeignTypeRef.Also, I was a bit unsure about what you meant here:
Are you saying that the compiler's treatment of
&Tdiffers enough from* constin C (even under a const-correct API) that this borrowing violation isn't actually problematic in practice?sfackler commentedon Nov 30, 2023
The
&selfis a pointer to UnsafeCell (semantically through a PhantomData). Why is it being tagged as Frozen?kornelski commentedon Nov 30, 2023
Could it be because
UnsafeCellinPhantomDatahas zero size, and doesn't exist in memory? If it wasOpaque(UnsafeCell<ActualForeignSizedType>)then it would map to an address space.madsmtm commentedon Nov 30, 2023
Yeah, I think there's a difference between
PhantomData<UnsafeCell<*mut ()>>andUnsafeCell<PhantomData<*mut ()>>, with only the latter registering as using interior mutabilityAdd as_mut_ptr
madsmtm commentedon Jan 16, 2024
I'll note again:
rustccurrently treatsUnsafeCelldifferently whether it's insidePhantomDataor not! See this playground, click "Show LLVM IR", and inspect the result; the function taking&PhantomData<UnsafeCell<*mut ()>>gets marked withnoalias readonly, while&UnsafeCell<PhantomData<*mut ()>>gets marked withreadnone.If you add extern types to the mix, you'll see the exact same LLVM IR as for
&UnsafeCell<PhantomData<*mut ()>>(LLVM will even merge the functions because of that).madsmtm commentedon Jan 16, 2024
See also discussion from rust-lang/unsafe-code-guidelines#236 (comment), this is still not determined
icmccorm commentedon Jan 16, 2024
@madsmtm I think you accidentally used the same link twice.
Based on this pull request, allowing
PhantomDatato apply interior mutability would be a breaking change, so it's not likely to be resolved in this direction soon. It seems like it would be worthwhile to changeOpaquefor now until the semantics are settled.madsmtm commentedon Jan 16, 2024
Apologies, I've fixed it now.
taikulawo commentedon Jan 20, 2025
From my view,
Opaqueis zero size type,So SslRef should be ZST
Does we convert pointer(for example,
*mut ffi::SSL) to SslRef is soundness?