diff --git a/unix/ifreq_linux.go b/unix/ifreq_linux.go index 309f5a2b0..3f7fa7664 100644 --- a/unix/ifreq_linux.go +++ b/unix/ifreq_linux.go @@ -22,7 +22,13 @@ import ( // fields can be get and set using the following methods: // - Uint16/SetUint16: flags // - Uint32/SetUint32: ifindex, metric, mtu -type Ifreq struct{ raw ifreq } +type Ifreq struct { + // Aligns the union for the accessors below, which cast it in place; + // the generated ifreq is all byte arrays, so its alignment is one. + _ [0]int64 + + raw ifreq +} // NewIfreq creates an Ifreq with the input network interface name after // validating the name does not exceed IFNAMSIZ-1 (trailing NULL required) diff --git a/unix/ifreq_linux_test.go b/unix/ifreq_linux_test.go index f10040bda..67188c622 100644 --- a/unix/ifreq_linux_test.go +++ b/unix/ifreq_linux_test.go @@ -172,3 +172,18 @@ func testIfreq(t *testing.T) *Ifreq { return ifr } + +func TestIfreqAlignment(t *testing.T) { + // The accessors cast the union in place, so it must be aligned for the + // widest type they use. Merely slow on amd64; a fault on sparc64. + want := unsafe.Alignof(uint32(0)) + if a := unsafe.Alignof(RawSockaddrInet4{}); a > want { + want = a + } + if got := unsafe.Alignof(Ifreq{}); got%want != 0 { + t.Errorf("unsafe.Alignof(Ifreq{}) = %d, want a multiple of %d", got, want) + } + if off := unsafe.Offsetof(Ifreq{}.raw) + unsafe.Offsetof(ifreq{}.Ifru); off%want != 0 { + t.Errorf("union lies at offset %d within Ifreq, want a multiple of %d", off, want) + } +}