-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
zero-sized slices are sometimes placed at 0x1 (1.79+) #128257
Comments
.as_ptr
doesn't always return a pointer in some situations (1.79+).as_ptr()
doesn't always return a pointer in some situations (1.79+)
@rustbot label -needs-triage -C-bug +C-discussion |
It also requires the type, These are both constants and the compiler can, by definition, even if we allocate them somewhere in the binary, put them anywhere. It is also permitted to e.g. take these two strings and make the relevant assert pass. Or not. You shouldn't rely on the address of constants, only a let x = "lol, lmao";
let y = "lol";
assert_eq!(x.as_ptr(), y.as_ptr()); The PR in question was #123936 |
.as_ptr()
doesn't always return a pointer in some situations (1.79+)
Could you explain what code you are concerned about that this change breaks, and if it differs from either of these cases? |
Here's my problem with this, the ZST is somehow being extended to a type that isn't a ZST or could be changed to a DST. For instance:
It feels like a ZST should only exist in the context of construction, but in later contexts, the type alone is not enough to express that something is a ZST. Like The code where I am running into issues is similar to FFI. In our case it's a syscall that is used for interfacing a guest running in a virtual machine with a host. The actual test case is:
The I think everything would be fine if we could just detect (ideally at compile-time) and disallow ZSTs from calling
which eventually calls:
|
I suppose we could check for a |
So the syscall itself performs undefined behavior on being told that it should read and write 0 bytes, and you do not have control over how it behaves? |
You should not be accessing more than 0 bytes behind a slice with length 0, that's UB no matter where the pointer is. I don't see the issue here without knowing exactly what you're doing with that pointer. |
What, exactly, is the actual problem? Does the program now segfault where it previously did not? |
In our hypervisor, we are checking that addresses that are sent from the guest do not land in the NULL page (0x0000 - 0x0400). This breaks that assumption and so an assertion is firing. I think we were under the impression that a pointer would always look and feel like a pointer, and that it would come from a region of memory that was either in I suppose we can add more checks that if a slice has a length of |
There is no requirement I am aware of that a pointer to a 0-length slice must point inside the range of any of the locations you mentioned. |
It would be, for instance, also permissible for us to make these pointers all instead point at |
The change here was not to the documented behavior of a stable API (we never guaranteed any particular pointer value or range), so there's no semver reason to forbid it. Your system accidentally depended on an implementation detail, and we must be allowed to change implementation details. |
Also I'm surprised you didn't run into this before, empty fn main() {
let v: Vec<u8> = Vec::new();
println!("{:?}", v.as_ptr());
} prints 0x1 since Rust 1.0. |
Iirc zero-sized pointers often get their values from the logic of
What exactly does this check - that anything with a pointer type doesn't have a value < 0x0400, or that accesses don't hit that address? It would seem unusual to somehow check the value rather than the accesses, and I am curious how this is done if this is the case. Having a NULL pointer in existence certainly shouldn't be an issue, but accessing it is obviously a fault. |
About "every cycle is precious", @flaub: It may interest you to know that in C, all of the mem* family of functions must also assume that passing a pointer that does not point to any byte within bounds of an existing object, but with an argument of 0, cannot be made undefined. This is because the pointer may be the "1 past the end" pointer. Obviously a pointer to 0x01 is a problem, but that is why N3261 proposes to simply accept memcpy, etc. on null pointers, and LLVM's mem* intrinsics specifically allow doing so on invalid pointers (like our dangling 0x01 pointers) as well. Note this implies it would be, e.g., valid for LLVM to replace any pointer that eventually becomes an argument to these intrinsics, but has a len of 0, with another pointer. Perhaps null, or perhaps one with an address of 0x01? LLVM assumes that the system's libc handles this sort of thing correctly. In practice, they do, as mentioned by that paper. So I must ask, is this syscall truly so hot that it is hotter than memcpy? But that is all of academic interest. There does not seem to be a problem here? This is unfortunately no different than relying on us emitting 10 instructions instead of 9 or 11 for a given function: it's an optimizing compiler, not a macro assembler. |
Thanks all for the discussion. We'll adjust the assertion to only fire if the length of a slice is non-zero. |
A pointer is allowed to be any undefined value if the length is 0. See: rust-lang/rust#128257
A pointer is allowed to be any undefined value if the original slice's length is 0. See: rust-lang/rust#128257
A pointer is allowed to be any undefined value if the original slice's length is 0. See: rust-lang/rust#128257
This is a backport of #2137 A pointer is allowed to be any undefined value if the original slice's length is 0. See: rust-lang/rust#128257
A pointer is allowed to be any undefined value if the original slice's length is 0. See: rust-lang/rust#128257
I tried this code:
In 1.78, this is the output:
However on 1.79+, this is the output:
How can this not be a major breaking change? It doesn't seem sensible that
as_ptr()
can return a value like0x01
.Meta
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: