-
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
use checked casts and arithmetic in Miri engine #70226
Conversation
Only Did we really future-proof the standard library for 128-bit address spaces? |
Yeah, exactly that. And that is quite annoying. Maybe the compiler should have its own Anyway, I made this a bit less annoying for Miri by now having both |
let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize); | ||
let v = f.to_u128(width).value; | ||
let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits()); | ||
let v = f.to_u128(usize::try_from(width).unwrap()).value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is apfloat using usize
instead of u64
for sizes...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, it could be an u8
just as well, the max value here is 128
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO it would make sense to consistently use the same type for sizes, that avoids casts. Note how changing bit_width
to return u64
got rid of a bunch of casts both in Miri and codegen.
|
||
#[inline] | ||
pub fn from_bits(bits: u64) -> Size { | ||
pub fn from_bits(bits: impl TryInto<u64>) -> Size { | ||
let bits = bits.try_into().ok().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this result in a worse panic message than if you remove the .ok()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah but it doesn't compile without the ok()
as we don't know if the error type implements Debug
.
pub const fn from_bytes(bytes: u64) -> Size { | ||
Size { raw: bytes } | ||
pub fn from_bytes(bytes: impl TryInto<u64>) -> Size { | ||
Size { raw: bytes.try_into().ok().unwrap() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here (removing the .ok()
).
This comment has been minimized.
This comment has been minimized.
pub fn mplace_index( | ||
&self, | ||
base: MPlaceTy<'tcx, M::PointerTag>, | ||
index: u64, | ||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is partially a duplication of logic in mplace_field
-- but note that that already was a duplication of logic in the layout code. We cannot use the layout code as it is written for usize
.
Allocation { | ||
bytes: vec![0; size.bytes() as usize], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe give Size
a method bytes_usize
which does this check for you so it isn't spread around everywhere. Make it #[track_caller]
though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added bytes_usize
, but was worried track_caller
would be bad for performance.
"cannot handle this access on this host architecture" | ||
); | ||
let end = end.bytes() as usize; | ||
let end = Size::add(offset, size); // This does overflow checking. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the Size::bin_op
style very much. Why are the regular binary operators not ok?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I see a +
I have to assume it is not overflow-checked. Figuring out the type of the operands can be non-trivial. So the only way to write overflow-clean Rust code for sure is to make sure there is, syntactically, no +
/*
/*-anywhere in the code. Hence the explicit
Size::{add,mul}`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alternative is to just turn on overflow checks in release mode.
I still don't like it. This is much less readable and most of the time the types are a line or two above in the arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not gonna block the PR on it, but I want someone else to also say it's ok to write lisp-math in rustc if infix math would produce the exact same machine code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I did the audit, I think I'm fine going back to infix notation. I will add a comment though in places where the type is not immediately obvious.
The alternative is to just turn on overflow checks in release mode.
Would be great if that could be controlled on a per-module basis. Given that this is a MIR building thing, I see no reason why per-module should not be possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could probably start out with a rustc_overflow_checks
attribute, seems straight forward enough to do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could probably start out with a rustc_overflow_checks attribute, seems straight forward enough to do.
@oli-obk's comment (#70226 (comment)) reminded me there used to be this pattern: let x: u128 = ...; // Some potentially large value...
let x_as_u64 = x as u64; // ... that we want to fit in a smaller type
assert_eq!(x_as_u64 as u128, x);
// Use `x_as_u64` now that it's been validated. I believe that |
@eddyb Indeed as part of this PR I replaced all instances of this pattern that I found by |
☔ The latest upstream changes (presumably #70371) made this pull request unmergeable. Please resolve the merge conflicts. |
r=me after a rebase |
…rand of overflowing_signed_offset
Rebased. |
📌 Commit 7400955 has been approved by |
⌛ Testing commit 7400955 with merge cf1bd7d3721a751f3f7737ba56e6e73bee07b40e... |
use checked casts and arithmetic in Miri engine This is unfortunately pretty annoying because we have to cast back and forth between `u64` and `usize` more often that should be necessary, and that cast is considered fallible. For example, should [this](https://doc.rust-lang.org/nightly/nightly-rustc/rustc/mir/interpret/value/enum.ConstValue.html) really be `usize`? Also, `LayoutDetails` uses `usize` for field indices, but in Miri we use `u64` to be able to also handle array indexing. Maybe methods like `mplace_field` should be suitably generalized to accept both `u64` and `usize`? r? @oli-obk Cc @eddyb
@bors retry yielding to rollup (which also contains this one) |
⌛ Testing commit 7400955 with merge d38c9793e9a3fda2dc9d8a052f3998e9cc57c1ad... |
@bors retry yielding to rollup |
Rollup of 5 pull requests Successful merges: - rust-lang#70226 (use checked casts and arithmetic in Miri engine) - rust-lang#70319 (correctly normalize constants) - rust-lang#70352 (Add long error explanation for E0710 ) - rust-lang#70366 (Implement Fuse with Option) - rust-lang#70379 (fix incorrect type name in doc comments) Failed merges: - rust-lang#70375 (avoid catching InterpError) r? @ghost
update miri Usually I'd wait until rust-lang#70226 lands which will break Miri again, but... the queue is empty (!), so whatever.^^ r? @ghost Cc @oli-obk Fixes rust-lang#70346
This is unfortunately pretty annoying because we have to cast back and forth between
u64
andusize
more often that should be necessary, and that cast is considered fallible.For example, should this really be
usize
?Also,
LayoutDetails
usesusize
for field indices, but in Miri we useu64
to be able to also handle array indexing. Maybe methods likemplace_field
should be suitably generalized to accept bothu64
andusize
?r? @oli-obk Cc @eddyb