A raw pointer by itself is just a few bytes storing some number, creating such a thing is perfectly safe.
fn main() {
let x = 1 as *const uint;
}
is a perfectly safe Rust program. Of course, such a thing is normally not useful, but the construction is not memory unsafe.
I opened #382 with the idea I mentioned above.
Yes, my point is removing *const would allow this to happen in unsafe code accidentally, in a hard-to-diagnose way, by just passing an immutable reference into a function that modifies it via a raw pointer. Saying “you should know what you’re doing” doesn’t cut it: unsafe code is hard to write correctly and throwing away an important piece of assistance seems very strange.
(Differing between optimisation levels is also surely worse than being always-broken.)
I don’t understand this at all. *const is definitely used in contexts were immutable memory makes sense, e.g. the second argument to memcpy. Using unsafe code does not mean “freely do anything you want”, it means “the compiler cannot verify this as safe, I am taking on the burden of proof”; in this context, keeping track of immutable memory and handling aliased data right is very important. Having a distinction between *const and *mut is useful for the programmer to get it right.
use std::{ptr, mem};
#[inline(never)]
fn foo(x: &int, y: &int) -> int {
let mut z = *x;
unsafe {
let new = *y + 10;
ptr::copy_memory(y as *const _ as *mut int, &new, mem::size_of::<int>());
}
z += *x;
z
}
fn main() {
let x = 1;
println!("{}", foo(&x, &x));
println!("{}", x);
}
has exactly the same problem as the transmute version. Imagine if it could be written as just ptr::copy_memory(y, &new, mem::size_of::<int>())? Debugging that seems hard: it could manifest as the result of some calculation being wrong occasionally, or some C call sometimes returning an error for no apparent reason (i.e. not necessarily appearing close to the code that is wrong).
If we were to only have a single pointer *, the problem above would be lessened by allowing implicit coercions from &mut to *, but disallowing coercions from & to *, but I feel like requiring explicit casts for that is likely to be worse than the status quo.
The main reason I know for casting *const to *mut is when using the freestanding offset function, which can be avoided via the method. Most other casts are taking a *mut to *const, which is (AFAICT) perfectly OK to perform implicitly, just like &mut to &.
I’m interested to know where other casts from *const to *mut occur; these should be looked on very suspiciously in general and we should try to make them necessary less often.
Rust references attach a very specific set of semantics to pointers, it’s very very reasonable to want to be attaching some other information/avoid the restrictions of references.
I don’t see how you can say “you shouldn’t use pointers in the first place”: there’s no alternative to using pointers for things like calling into C. Yes, you should know what you’re doing, but the chronic problems in C & C++ code demonstrate that it is not reasonable to expect correctness always.
I can’t think any way that this can reasonably be a lint other than via types, but am very interested to hear if you have a good proposal for how to handle the linting specifically.