I am currently reading the source code of rust and am interested in the underlying details of the Raw pointer, but when I googled the information I found a problem, most of the information is only general and does not cover the essence of the Raw pointer, how can I understand the Raw pointer and the underlying details of the encapsulation of rust from the ground up?
I have a little bit of experience with c and I know that rust Raw pointers are more complex than c.
The same as any other language with raw pointers. They're the same size as usize, (64 bits on 64 bit machines, 32 bits on 32 bit machines). They're literally just an address into memory.
Well, raw pointers let you do things which would otherwise be unallowed such as keep two points of mutable access to an object. They also have a specified ABI when their pointee is Sized so you can pass them through FFI boundaries.
It's UB to dereference a raw pointer if it's not as valid as a reference would be.
In essence this means:
Your pointer is correctlty aligned to the pointee.
Your pointer points to an object in an initialized state.
Your pointer is not null.
You can allocate memory using the allocator in Rust with a particular size and alignment (that's wha the Layout struct is for) and that'll give you back a pointer. You're then guaranteed to have access to that data without:
A segfault
Overwriting other data you care about
(Although of course you must initialize it properly)
I'm not quite sure what you mean... if you're asking if memory has an inherent type then the answer is no but things can get tricky:
Transmuting objects by means of reading the wrong type from a raw pointer is usually UB.
Reading padding bytes is also usually UB.
Accessing specific fields in a #[repr(Rust)] (by default structs, enums, and unions have #[repr(Rust)] on them without being explicitly placed there) is UB if I recall correctly (you can only get an address to them if you specifically reference the pointee and offset methods aren't guaranteed to work).
Note that in Rust, memory itself is quite definitely untyped. If the bits, provenance, and initializedness are correct, you can legally read/write it regardless of how that memory was originally obtained.
(This is different from things like C++ that have TBAA, and thus certain kinds of reads are UB regardless of the bit pattern behind it.)
The provenance of pointers can't cross allocated objects. Maybe that's what you meant, but I'm not sure. The allocator hands out pointers that one eventually hands back. What exactly the allocator does can vary per allocator. But again, a typical Rust programmer won't be working on this level, they'll be working with Box (or Vec or...), or perhaps with MaybeUninit.
mumble mumble CHERI, but that's not a Rust specific thing either ↩︎
Rust does have one additional quirk, though: Raw pointers to unsized types, like *mut [u8] or *mut dyn Trait are fat pointers that contain some additional metadata in addition to the memory address. I believe that all of these are double-width at the moment, but the specifics are dependent on the target type— There’s a possibility that some types could have even wider pointers sometime in the future.
Generally, the metadata will either be a usize that describes the length of a slice or a pointer to a vtable used for dynamic method dispatch.