ioctl_write_int! wrong data size call
Greetings,
here's my setup :
aarch64-unknown-linux-gnurust 1.88.0gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0ldd (Ubuntu GLIBC 2.35-0ubuntu3.10) 2.35
The C IOCTL is defined with _IOW(IOCTL_MAGIC, 3, ulong)
I'm using ioctl_write_int!, docs specifies that nix::sys::ioctl::ioctl_param_type on linux is libc::c_ulong, which is 8 bytes.
I have checked that
- on rust side with
size_of::<nix::sys::ioctl::ioctl_param_type>(), reports 8 bytes - on C side with
sizeof(ulong), 8 bytes as well
However the ioctl cmd call I receive in my c driver is 0x4004f003 which decodes to dir=1 type=240 nr=3 size=4.
I couldn't figure where this could be coming from...
My current workaround is to set IOCTL to _IOW(IOCTL_MAGIC, 3, uint) as I'm ok with this type, but I'm confused by the mismatch.
Please let me know if I can bring more info to help !
I think this is the correct behavior for ioctl_write_int!, but there is a documentation bug, introduced by dc41be48a7 . I'm not sure why that commit introduced that change. Perhaps a merge conflict of some sort?
Ok I think I got the source of the problem :
- BSD case has
ioctl_num_typedefined as eitherc_intorc_ulongioctl_param_typedefined asc_intioctl_write_intis using a specific_IOWINTioctl type (which is not in linux), and which always usesc_int
- Linux case has
ioctl_num_typedefined as eitherc_intorc_ulongas wellioctl_param_typedefined asc_ulongioctl_write_intuses the standard_IOWbut givessize_of::<$crate::libc::c_int>()), independently of the generated rust fn's argumentdatatype which is always$crate::sys::ioctl::ioctl_param_type
so ultimately the confusion comes from the fact that for cfg(linux), the rust type is documented and generated as using ioctl_param_type (which is c_ulong),
BUT does not use sizeof::<ioctl_param_type> (uses c_int),
so there's a clear mismatch between all the hints given to user of the lib (fn type and doc), and what the actual generated function passes to the kernel call.
I think this is the correct behavior for ioctl_write_int!
It is indeed the correct behavior for BSD, but the _IOWINT doesn't exist on linux, hence this macro being adapted for it
As making a change on the generated ioctl call would be probably more breaking on the C side than changing the ioctl_param_type on rust side (would only need to add as _, and check over/underflow consequences),
changing back ioctl_param_type to c_int and updating the doc accordingly would seem like the most reasonable change to reduce confusion of lib users.
I can close the issue as my confusion is now cleared. I don't know if this change is even needed, as it's working without problem, but other people might stumble on this later as well.
I also ran into this issue. Was this determined to strictly be a documentation issue?
I had completely forgotten about this issue !
In the end I've just changed my C driver code to _IOW(IOCTL_MAGIC, NR_IO, u32) to keep using ioctl_write_int!() and to be sure that they're both using 4 bytes type. If I need u64 in the future I'll just use the more generic ioctl_write_ptr!().
I haven't got any more info nor feedback from this repo since my last message here, so still no confirmation if it was strictly documentation issue, or something else. I assume there were more important things to focus on, and the workaround is pretty easy to figure out.