Add checked arithmetic operations traits#298
Add checked arithmetic operations traits#298ncatelli wants to merge 30 commits intorust-osdev:masterfrom
Conversation
137cdef to
76ca2e9
Compare
|
I've made all requested changes and have mostly stuck to your requests directly, the only difference would be retention of the chain in the |
|
@ncatelli I've resolved all the comments that you've fixed (I think there are still a few more comment nits to fixed). Can you add implementations for the other address types ( |
|
Also @ncatelli per #293 (comment) can you remove the |
There was a problem hiding this comment.
Sorry about that. I had over looked the other changes you'd requested, these are now fixed.
I've implemented the trait for the additional types you requested for the types laid out in #293. I've left a few comments regarding preference questions on a few of the check calls. Since most of these questions apply to the implementations of both Page and PhysFrame, I've only left discussion comments on PhysFrame.
Again, thanks again for all the time, I know this PR and attached issue have been fairly high-touch.
|
|
||
| impl<S: PageSize> PhysFrame<S> { | ||
| /// Returns the frame that starts at the given virtual address. | ||
| /// Returns the frame that starts at the given physical address. |
There was a problem hiding this comment.
Small typo that I'd noticed and corrected. I just wanted to call it out explicitly since this was beyond the scope of the PR and just to spot-check my change
|
|
||
| const_fn! { | ||
| /// Returns the frame that starts at the given virtual address. | ||
| /// Returns the frame that starts at the given physical address. |
There was a problem hiding this comment.
Same as above, additional doc change.
| fn checked_sub(self, rhs: PhysFrame<S>) -> Option<Self::Output> { | ||
| self.start_address() | ||
| .checked_sub(rhs.start_address()) | ||
| .map(PhysAddr::new) |
There was a problem hiding this comment.
I opted for new, which can panic over try_new as the sub should prevent ever falling into panic inducing address space unless someone is doing something really bananas. I can happily change this to try_new if you would prefer since new just calls try_new under the hood. This would guarantee we entirely avoid a panic that I think won't ever even happen, but at the expense of denser code.
There was a problem hiding this comment.
Nevermind. The more i thought about this I opted to change it. The guarantee of no panic for a checked_* method should probably be the default.
There was a problem hiding this comment.
What is the point of converting the offset to a PhysAddr and PhysFrame? Couldn't you just write this?
self.start_address()
.checked_sub(rhs.start_address())
.map(|offset| offset / S::SIZE)There was a problem hiding this comment.
Hello, I opted for the case of safely validating of the address and the alignment as there are a few cases where an unaligned frame start address could be returned. This would necessitate the caller broke the contract of from_start_address_unchecked. I'm happy to change this method if you feel strongly about it.
There was a problem hiding this comment.
Because from_start_unchecked is marked as unsafe, we can always assume that the caller did not violate the safety requirements and we don't need to check for them again.
Even if the caller did violate the requirements, this would cause the function to fail as if an underflow occurred even when that's not the case, which seems a bit unexpected.
There was a problem hiding this comment.
Fair, the change you've requested has been made.
There was a problem hiding this comment.
I noticed that you also used this pattern in a few other places, those probably need to be changed too.
There was a problem hiding this comment.
Applied the same change to Page::checked_sub to match the same. By other's i assume you mean something like https://github.com/rust-osdev/x86_64/pull/298/files#diff-d2a15219d98ad66c2aeac0ee03d682034bc619fe5905e63960599aa58b7a63cfR332-R342, in which this was done for the sake of checking valid addresses of the multiple and I think there is no reason to change that.
There was a problem hiding this comment.
You don't need to check if the offset is a valid address, in fact it is wrong to do so. For addition it's perfectly fine to jump from the lower half of the address space to the upper half. In that case the offset is not necessarily a valid virtual address. Offsets just aren't the same as virtual (or physical) addresses.
I'm aware that there has been some discussion on whether we should allow jumping from the lower half to the upper half and I'm open to change in that direction. However for now we should make sure that the checked and non-checked implementations behave in the same way.
| fn checked_add(self, rhs: u64) -> Option<Self::Output> { | ||
| let phys_addr_rhs = rhs | ||
| .checked_mul(S::SIZE) | ||
| .and_then(|addr| PhysAddr::try_new(addr).ok())?; |
There was a problem hiding this comment.
Let me know if this is overkill and you'd like me to opt for a lighter weight checked op by removing the PhysAddr validity check.
|
Alright, that should be the last of my changes until the next review cycle. I wanted to make sure intent was either clear or documented with examples (that hopefully make it clear). |
|
One additional note, while I'm aware of the discussion in #293 about removing the |
|
Triage: This PR has been waiting for some time. @josephlr Do you have time for a new review, or should I try to take over? |
4d95a3a to
ad70df8
Compare
General
This is an initial attempt to define a
CheckedAddandCheckedSubset of traits per the traits discussed in the linked issue below. I've applied these traits to theaddressing types listed in the issue to check address, page and frame arithmetic.VirtAddrRelated Issues
#293