Document number casting safety across platform boundaries#78
Conversation
Co-authored-by: Nugine <30099658+Nugine@users.noreply.github.com>
Co-authored-by: Nugine <30099658+Nugine@users.noreply.github.com>
|
@copilot Try to avoid clippy warnings without explicit allowance. |
Co-authored-by: Nugine <30099658+Nugine@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds comprehensive safety documentation for numeric type conversions between Rust and C/libc types across different platforms. The changes explain why casts between types like u64 ↔ rlim_t (Unix) and u32 ↔ c_int (Windows) are safe, with particular attention to platform-specific type size variations.
Key changes:
- Added SAFETY comments explaining the rationale for all numeric casts involving platform-dependent types
- Documented that clamping to
INFINITYprevents truncation issues on 32-bit platforms - Clarified that validation checks ensure casts behave correctly
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/unix.rs | Documents rlim_t ↔ u64 conversion safety with INFINITY clamping for cross-platform compatibility |
| src/windows.rs | Documents c_int ↔ u32 conversion safety with validation and sign checks |
| src/tools.rs | Documents c_int → u64 widening conversion safety for sysctl return values |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // SAFETY: We've validated that new_max fits in c_int, so the cast is safe | ||
| // (though clippy warns about possible wrapping). The cast back to u32 is | ||
| // safe because we've checked that ret >= 0. |
There was a problem hiding this comment.
The SAFETY comment here is misleading. The cast on line 38 (new_max as c_int) is not made safe by the validation check - the check simply ensures the cast won't wrap around to a negative value. The actual cast can still wrap (which is why clippy warns about it), but we've verified that the wrapped value would be correct for this specific case.
Similarly, the cast on line 42 (ret as u32) is not made "safe because we've checked that ret >= 0" - the non-negativity check prevents sign loss from being a problem, but the cast itself still involves sign loss.
The comment should clarify that the validation ensures the cast behaves correctly (doesn't produce a negative number), rather than claiming the cast itself becomes "safe".
| // SAFETY: c_int::MAX (i32::MAX = 2147483647) fits in u32, so this cast is safe. | ||
| if new_max > c_int::MAX as u32 { |
There was a problem hiding this comment.
The SAFETY comment on line 25 is misplaced and potentially confusing. It's attached to a validation check that prevents overflow, not to an actual unsafe cast. The cast on line 26 (c_int::MAX as u32) is indeed safe since i32::MAX fits in u32, but this comment should be placed directly above line 26 where the cast occurs, not above the conditional statement. Additionally, the comment should clarify that it's explaining why the comparison operation's cast is safe, not why the validation itself is safe.
| // SAFETY: c_int::MAX (i32::MAX = 2147483647) fits in u32, so this cast is safe. | |
| if new_max > c_int::MAX as u32 { | |
| if new_max > { | |
| // SAFETY: c_int::MAX (i32::MAX = 2147483647) fits in u32, so this cast in the comparison is safe. | |
| c_int::MAX as u32 | |
| } { |
| /// This constant is the minimum of the platform's `RLIM_INFINITY` and `u64::MAX`. | ||
| /// On most platforms, `RLIM_INFINITY` is already `u64`, making this cast lossless. |
There was a problem hiding this comment.
The documentation states "This constant is the minimum of the platform's RLIM_INFINITY and u64::MAX", but this is technically imprecise. The constant is actually the result of casting RLIM_INFINITY to u64, which is not the same as taking the minimum. On platforms where rlim_t is u32, this cast widens the value (e.g., u32::MAX becomes u64 equivalent), not takes a minimum. The comment should say something like "This constant is RLIM_INFINITY cast to u64" or describe the actual behavior more accurately.
| /// This constant is the minimum of the platform's `RLIM_INFINITY` and `u64::MAX`. | |
| /// On most platforms, `RLIM_INFINITY` is already `u64`, making this cast lossless. | |
| /// This constant is the platform's `RLIM_INFINITY` cast to `u64`. | |
| /// On most platforms, `RLIM_INFINITY` is already `u64`, making this cast lossless. | |
| /// On platforms where `rlim_t` is smaller (e.g., `u32`), this cast widens the value. |
Added safety documentation for all type conversions between Rust and libc types, particularly for cross-platform scenarios where type sizes vary.
Changes
unix.rs -
rlim_t ↔ u64conversionsINFINITYbefore downcasting prevents truncation on 32-bit platformsrlim_tare lossless (u64→u64) or widening (u32→u64)windows.rs -
c_int ↔ u32conversionsnew_max ≤ c_int::MAXbefore castingtools.rs -
c_int → u64conversionAdded inline SAFETY comments explaining the safety rationale for all casts without introducing unnecessary clippy allow attributes.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.