-
Notifications
You must be signed in to change notification settings - Fork 347
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
implement intptrcast model #224
Comments
My plan was to go even further and essentially implement the intptrcast-model. That would immediately make us support all pointer arithmetic. Essentially, I think at some point miri should (in non-CTFE mode!) guarantee that safe Rust code can not error out (if the unsafe libraries it uses don't contain bugs). So hashing raw pointers and printing them and stuff like that all have to work. |
Sounds reasonable to me. Once a pointer has been observed and thus it's integral representation is available, there's no way in safe code to go from that pointer back to the allocation, so we don't even need to support that direction, right? All we need to ensure is hat the integral representation doesn't change when obtaining it multiple times from a real pointer We'll also need to generate an integer address when offsetting pointers due to overflow concerns. Overflowing exposes the address essentially. |
That's only true when you do the offsetting after casting to integer though, is it? The offset operations on pointers don't let safe code observe whether an overflow actually happened. Really, we could just generate an integer address immediately on allocation. Doing lookup on a |
Well... You can do let x = 5;
for i in 1.. {
let ptr = &x as *const i32;
let ptr2 = ptr.wrapping_offset(i);
if ptr2 <= ptr {
println!("Address of `x` is {}", std::usize::max_value() - i);
}
}
We'd run out of integer addresses eventually (and quickly on 32bit emulation) if we don't reuse integer addresses and create a unique integer address for every allocation. |
Heh, nice catch.
"Quickly"? 2^32 is still a large number, I feel.^^ |
The problem is, that once you leak the base address of an array, you also leak the address of the last element's last byte. So allocatingand deallocating 100MB 50 times would fill the address space unless we allow reusing it. |
Actually, given what I wrote in https://internals.rust-lang.org/t/types-as-contracts/5562/81, I think it would make sense for miri to both support pointer comparisons on "abstract" pointers and only provide intptrcast optionally. Without intptrcast, there will always be safe code that miri cannot run (like printing the value of a pointer), but currently there still seems to be value in also having a mode that keeps pointers and integers more separate. |
This code currently fails on miri: fn main() {
let x: Vec<u32> = Vec::new();
&x == &[];
}
|
Blocked on #653 |
cc @christianpoveda Basic (meaning probably incomplete) implementation instructions:
|
Ok I'll start working on this :D i'll be working on this branch: https://github.com/christianpoveda/rust/tree/intptrcast-model |
Should I wait for rust-lang/rust#59654? |
nah. whoever comes last needs to rebase ;) |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I'm on step 1 and got errors when running tests, the linker is failing and I'm not even sure if its my fault, these are the changes: rust-lang/rust@master...christianpoveda:intptrcast-model |
I never run What is your |
|
When just working on the Miri engine, I'd recommend The error you are running into looks like a bug, might be worth reporting if you can reproduce it on unchanged master. |
Ok, I've added the helper method into |
Well, many of the places where we use Given that one can transmute between integers and pointers, and that not all valid pointers are even representable as
|
Ok, I'll start digging then :D |
This is an small update:
After that I think that this part is ready for PR, the other changes must be done in miri AFAIK. Is that ok? |
Ok I might have a problem, both |
The machine hooks should likely just take a |
I've changed the However, I've been replacing
Could you take a look? rust-lang/rust@master...christianpoveda:intptrcast-model Edit: Its already solved, I'm doing some tests now. |
I replaced some of the Update: I modified |
That looks odd, there shouldn't be two calls to But I think @oli-obk is right, this is not very nice either. Let's move this refactoring to later, doesn't have to happen now. For now, keep the dispatching the way it was. |
…-obk Implement intptrcast methods cc #224
Some discussion between eddyb and me about miri and threads came to the conclusion that for certain kind of checks it would be helpful to only have the intptrcast part where you can go from ptr to int, but not the other way. I believe that would even cover most real use cases, as I've only seen the other direction in artificial examples so far |
I don't understand what you even mean by that. Could you give some concrete examples of programs we should not support and why? Also see this Zulip discussion. |
well, basically I want to forbid (on 64 bit) union Foo {
a: (u32, u32),
b: usize,
}
let (x, y) = Foo { b: &1 as *const i32 as usize }.a;
let ptr = ((x as usize) << 32) | (y as usize);
let ptr = *(ptr as *const i32); or any other bit modifying operations beyond those below the alignment (so those that will happen on the integer representation instead of on the abstract representation). You can do these reading operations, so you can print all bits of a pointer, I just want to forbid |
I'd rather get rid of all the code that performs arithmetic on the Why don't you want to allow that code? I do want to forbid this code which is why I added a test for this, but yours seems fine to me. |
Essentially to be able to do full thread separation via our symbolic pointers. I want to be able to leverage the knowledge about what is accessible where. If we have integer pointers, that becomes impossible. |
I'm afraid you will have to tell me more, I still don't know what this is all about.^^ Can you open a new issue for this specific restriction, and describe in more detail the why and how? My plan is to close this one once everything works. I should probably put a checklist in the first comment here for what is still on @christianpoveda's TODO list. ;) |
Plz do |
Done. :) |
Turns out instead of calling |
Since right now miri's pointer comparison bails out on
&x as *const T < &y as *const T
but allows&x as *const T == &y as *const T
, I suggest to also allow<
. This will not impact ctfe-mode, since ctfe mode disallows any binary ops on pointers into different allocs, even==
.It's deterministic between multiple miri runs, doesn't leak
HashMap
ordering and only depends on optimizations and codegen from rustc (but that's already true for==
).Steps to do:
check_ptr_access
? Redundant with validity checks but whatever.) We may need aforce_ptr_place
method or so; the freeze-sensitive visitor also needs that.force_bits when doing partial loads of a pointer -- and really everywhere we need a ptr, once it is total. (For now let's not do this, also see const-eval: load of partially initialized scalar produces entirely uninitialized result rust#69488 for a similar problem around partially initialized data.)to_<int type>
methods...), to_ptr and to_bits_or_ptr, all uses of is_ptr and is_bits, and also all uses offorce_ptr
andforce_mplace_ptr
(alsomplace_access_checked
,check_mplace_access
) outside ofcheck_ptr_access
. Maybe replace to_{bits,ptr} by assert_{bits,ptr}?The text was updated successfully, but these errors were encountered: