authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-01 17:18:30-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-02 16:30:59-07:00
log062d17ccab495d63799e3ac8831eed485ca8cffe
tree4699f832c8636c72644fe3b5fd3d1ef1f4e0ab42
parent96cf75977bd46ccf4d0626183bc1d9e3e5d80eac

std: fix msghdr and cmsghdr when using musl libc

glibc and linux kernel use size_t for some field lengths while POSIX and musl use int. This bug would have caused breakage the first time someone tried to call sendmsg on a 64-bit big endian system when linking musl libc. my opinion: * msghdr.iovlen: kernel and glibc have it right. This field should definitely be size_t. With int, the padding bytes are wasted for no reason. * msghdr.controllen: POSIX and musl have it right. 4 bytes is plenty for the length, and it saves 4 bytes next to flags. * cmsghdr.len: POSIX and musl have it right. 4 bytes is plenty for the length, and it saves 4 bytes since the other fields are also 32-bits each.

2 files changed, 44 insertions(+), 59 deletions(-)

lib/std/c.zig+41-59
......@@ -4185,8 +4185,9 @@ pub const linger = switch (native_os) {
41854185 },
41864186 else => void,
41874187};
4188
41884189pub const msghdr = switch (native_os) {
4189 .linux => linux.msghdr,
4190 .linux => if (@bitSizeOf(usize) > @bitSizeOf(i32) and builtin.abi.isMusl()) posix_msghdr else linux.msghdr,
41904191 .openbsd,
41914192 .emscripten,
41924193 .dragonfly,
......@@ -4201,36 +4202,24 @@ pub const msghdr = switch (native_os) {
42014202 .tvos,
42024203 .visionos,
42034204 .watchos,
4204 => extern struct {
4205 /// optional address
4206 name: ?*sockaddr,
4207 /// size of address
4208 namelen: socklen_t,
4209 /// scatter/gather array
4210 iov: [*]iovec,
4211 /// # elements in iov
4212 iovlen: i32,
4213 /// ancillary data
4214 control: ?*anyopaque,
4215 /// ancillary data buffer len
4216 controllen: socklen_t,
4217 /// flags on received message
4218 flags: i32,
4219 },
4220 // https://github.com/SerenityOS/serenity/blob/ac44ec5ebc707f9dd0c3d4759a1e17e91db5d74f/Kernel/API/POSIX/sys/socket.h#L74-L82
4221 .serenity => extern struct {
4222 name: ?*anyopaque,
4223 namelen: socklen_t,
4224 iov: [*]iovec,
4225 iovlen: c_int,
4226 control: ?*anyopaque,
4227 controllen: socklen_t,
4228 flags: c_int,
4229 },
4205 .serenity, // https://github.com/SerenityOS/serenity/blob/ac44ec5ebc707f9dd0c3d4759a1e17e91db5d74f/Kernel/API/POSIX/sys/socket.h#L74-L82
4206 => private.posix_msghdr,
42304207 else => void,
42314208};
4209
4210/// https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_socket.h.html
4211const posix_msghdr = extern struct {
4212 name: ?*sockaddr,
4213 namelen: socklen_t,
4214 iov: [*]iovec,
4215 iovlen: u32,
4216 control: ?*anyopaque,
4217 controllen: socklen_t,
4218 flags: u32,
4219};
4220
42324221pub const msghdr_const = switch (native_os) {
4233 .linux => linux.msghdr_const,
4222 .linux => if (@bitSizeOf(usize) > @bitSizeOf(i32) and builtin.abi.isMusl()) posix_msghdr_const else linux.msghdr_const,
42344223 .openbsd,
42354224 .emscripten,
42364225 .dragonfly,
......@@ -4245,36 +4234,25 @@ pub const msghdr_const = switch (native_os) {
42454234 .tvos,
42464235 .visionos,
42474236 .watchos,
4248 => extern struct {
4249 /// optional address
4250 name: ?*const sockaddr,
4251 /// size of address
4252 namelen: socklen_t,
4253 /// scatter/gather array
4254 iov: [*]const iovec_const,
4255 /// # elements in iov
4256 iovlen: u32,
4257 /// ancillary data
4258 control: ?*const anyopaque,
4259 /// ancillary data buffer len
4260 controllen: socklen_t,
4261 /// flags on received message
4262 flags: i32,
4263 },
4264 .serenity => extern struct {
4265 name: ?*const anyopaque,
4266 namelen: socklen_t,
4267 iov: [*]const iovec_const,
4268 iovlen: c_uint,
4269 control: ?*const anyopaque,
4270 controllen: socklen_t,
4271 flags: c_int,
4272 },
4237 .serenity,
4238 => posix_msghdr_const,
42734239 else => void,
42744240};
4241
4242const posix_msghdr_const = extern struct {
4243 name: ?*const sockaddr,
4244 namelen: socklen_t,
4245 iov: [*]const iovec_const,
4246 iovlen: u32,
4247 control: ?*const anyopaque,
4248 controllen: socklen_t,
4249 flags: u32,
4250};
4251
42754252pub const cmsghdr = switch (native_os) {
4253 .linux => if (@bitSizeOf(usize) > @bitSizeOf(i32) and builtin.abi.isMusl()) posix_cmsghdr else linux.cmsghdr,
42764254 // https://github.com/emscripten-core/emscripten/blob/96371ed7888fc78c040179f4d4faa82a6a07a116/system/lib/libc/musl/include/sys/socket.h#L44
4277 .linux, .emscripten => linux.cmsghdr,
4255 .emscripten => linux.cmsghdr,
42784256 // https://github.com/freebsd/freebsd-src/blob/b197d2abcb6895d78bc9df8404e374397aa44748/sys/sys/socket.h#L492
42794257 .freebsd,
42804258 // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/107c0518337ba90e7fa49e74845d8d44320c9a6d/sys/sys/socket.h#L452
......@@ -4298,13 +4276,17 @@ pub const cmsghdr = switch (native_os) {
42984276 .tvos,
42994277 .visionos,
43004278 .watchos,
4301 => extern struct {
4302 len: socklen_t,
4303 level: c_int,
4304 type: c_int,
4305 },
4279 => posix_cmsghdr,
4280
43064281 else => void,
43074282};
4283
4284const posix_cmsghdr = extern struct {
4285 len: socklen_t,
4286 level: c_int,
4287 type: c_int,
4288};
4289
43084290pub const nfds_t = switch (native_os) {
43094291 .linux => linux.nfds_t,
43104292 .emscripten => emscripten.nfds_t,
lib/std/os/linux.zig+3
......@@ -9751,8 +9751,10 @@ pub const msghdr = extern struct {
97519751 name: ?*sockaddr,
97529752 namelen: socklen_t,
97539753 iov: [*]iovec,
9754 /// The kernel and glibc use `usize` for this field; POSIX and musl use `c_int`.
97549755 iovlen: usize,
97559756 control: ?*anyopaque,
9757 /// The kernel and glibc use `usize` for this field; POSIX and musl use `socklen_t`.
97569758 controllen: usize,
97579759 flags: u32,
97589760};
......@@ -9769,6 +9771,7 @@ pub const msghdr_const = extern struct {
97699771
97709772// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/socket.h?id=b320789d6883cc00ac78ce83bccbfe7ed58afcf0#n105
97719773pub const cmsghdr = extern struct {
9774 /// The kernel and glibc use `usize` for this field; musl uses `socklen_t`.
97729775 len: usize,
97739776 level: i32,
97749777 type: i32,