-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Transmute big endian s6_addr
and [u16; 8]
#75085
Conversation
Wow. Lots of tests are falling. I should reconsider this approach. |
library/std/src/net/ip.rs
Outdated
h as u8, | ||
], | ||
// SAFETY: Each element of `s6_addr16` is big edian. | ||
s6_addr: unsafe { in6_union { s6_addr16: [a, b, c, d, e, f, g, h] }.s6_addr }, |
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 assumption here is wrong about arguments: (a
, b
, ...).
Those are not guaranteed to be Big Endian.
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.
Right, the parameters are native-endian, and the output from segments
is native too.
Maybe you could use [a.to_be_bytes(), b.to_be_bytes, ...]
to get [[u8; 2]; 8]
instead, and then cast that into s6_addr
. But once we're dealing with byte swaps, your godbolt advantage may disappear, so I think this will only be a matter of code style.
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.
Or [a.to_be(), b.to_be(), ...]
to get a [u16; 8]
directly that is big endian.
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 actually does lead to better instructions: https://rust.godbolt.org/z/dv4Pje
I'm pretty sure this means that if you're on a little endian system you have to byte swap your shorts before writing them to this structure. So you'd have to do |
Thanks both. I will resolve it later. |
a849a4a
to
8eacf7d
Compare
44c7f27
to
c7d37c5
Compare
Instead of the temporary union, have you tried |
Where is it defined? I can only find this: rust/src/librustc_codegen_ssa/mir/block.rs Lines 1343 to 1380 in f50f1c8
|
It would work. But we may lose all safety comments that documented in Ipv6Bytes. |
We could move those safety comments to unsafe transmute, the good thing is it will be shorter, the bad thing is hard to test and track the unsafe (probably). |
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.
Looks good to me.
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.
Please update the PR title to "transmute".
s6_addr
and [u16; 8]
The old code already made the assumption to reinterpret `Ipv6Addr` as `[u16; 8]`. Glibc, Linux, FreeBSD, Win32 all makes this assumption. The main motivation of using union it to better optimize code. ref: * https://docs.microsoft.com/en-us/windows/win32/api/in6addr/ns-in6addr-in6_addr * https://github.com/freebsd/freebsd/blob/1d6e4247415d264485ee94b59fdbc12e0c566fd0/contrib/ntp/lib/isc/include/isc/ipv6.h#L63 * https://github.com/zephyrproject-rtos/zephyr/blob/8b531aa996bba254c03129658490af59597acd78/include/net/net_ip.h#L137 * https://sourceware.org/git/?p=glibc.git;a=blob;f=inet/netinet/in.h;h=f6355c7efe5192b88337b136ef687fe9a5ed648c;hb=HEAD#l216 Co-authored-by: Josh Stone <cuviper@gmail.com> Co-authored-by: Peter Atashian <retep998@gmail.com>
@bors r+ |
📌 Commit 0210fd3 has been approved by |
⌛ Testing commit 0210fd3 with merge 6b1e00131ee7682486cfc5f45ffb1966b89d4a81... |
💔 Test failed - checks-azure |
Hmm, macOS builds didn't start. |
@bors retry rollup |
Rollup of 10 pull requests Successful merges: - rust-lang#74744 (Update RELEASES.md for 1.46.0) - rust-lang#75085 (Transmute big endian `s6_addr` and `[u16; 8]`) - rust-lang#75226 (Miri: Renamed "undef" to "uninit") - rust-lang#75333 (polymorphize: constrain unevaluated const handling) - rust-lang#75338 (move stack size check to const_eval machine) - rust-lang#75347 (Rustdoc: Fix natural ordering to look at all numbers.) - rust-lang#75352 (Tweak conditions for E0026 and E0769) - rust-lang#75353 (Tiny cleanup, remove unnecessary `unwrap`) - rust-lang#75359 (unused_delims: trim expr) - rust-lang#75360 (Add sample fix for E0749) Failed merges: r? @ghost
Make all methods of `std::net::Ipv6Addr` const Make the following methods of `std::net::Ipv6Addr` unstable const under the `const_ipv6` feature: - `segments` - `is_unspecified` - `is_loopback` - `is_global` (unstable) - `is_unique_local` - `is_unicast_link_local_strict` - `is_documentation` - `multicast_scope` - `is_multicast` - `to_ipv4_mapped` - `to_ipv4` This would make all methods of `Ipv6Addr` const. Changed the implementation of `is_unspecified` and `is_loopback` to use a `match` instead of `==`, all other methods did not require a change. All these methods are dependent on `segments`, the current implementation of which requires unstable `const_fn_transmute` ([PR#75085](rust-lang#75085)). Part of rust-lang#76205
Stabilize all stable methods of `Ipv4Addr`, `Ipv6Addr` and `IpAddr` as const This PR stabilizes all currently stable methods of `Ipv4Addr`, `Ipv6Addr` and `IpAddr` as const. Tracking issue: rust-lang#76205 `Ipv4Addr` (`const_ipv4`): - `octets` - `is_loopback` - `is_private` - `is_link_local` - `is_multicast` - `is_broadcast` - `is_docmentation` - `to_ipv6_compatible` - `to_ipv6_mapped` `Ipv6Addr` (`const_ipv6`): - `segments` - `is_unspecified` - `is_loopback` - `is_multicast` - `to_ipv4` `IpAddr` (`const_ip`): - `is_unspecified` - `is_loopback` - `is_multicast` ## Motivation The ip methods seem like prime candidates to be made const: their behavior is defined by an external spec, and based solely on the byte contents of an address. These methods have been made unstable const in the beginning of September, after the necessary const integer arithmetic was stabilized. There is currently a PR open (rust-lang#78802) to change the internal representation of `IpAddr{4,6}` from `libc` types to a byte array. This does not have any impact on the constness of the methods. ## Implementation Most of the stabilizations are straightforward, with the exception of `Ipv6Addr::segments`, which uses the unstable feature `const_fn_transmute`. The code could be rewritten to equivalent stable code, but this leads to worse code generation (rust-lang#75085). This is why `segments` gets marked with `#[rustc_allow_const_fn_unstable(const_fn_transmute)]`, like the already const-stable `Ipv6Addr::new`, the justification being that a const-stable alternative implementation exists rust-lang#76206 (comment). ## Future posibilities This PR const-stabilizes all currently stable ip methods, however there are also a number of unstable methods under the `ip` feature (rust-lang#27709). These methods are already unstable const. There is a PR open (rust-lang#76098) to stabilize those methods, which could include const-stabilization. However, stabilizing those methods as const is dependent on `Ipv4Addr::octets` and `Ipv6Addr::segments` (covered by this PR).
The old code already made the assumption to reinterpret
Ipv6Addr
as[u16; 8]
.Glibc, Linux, FreeBSD, Win32 all makes this assumption.
The main motivation of using union it to better optimize code.
Godbolt: https://rust.godbolt.org/z/sdP4Pc
Const is introducing unsafe when transmuting.
ref: