Some ioctl(2) calls have been rather poorly specified in the past. Unfortunately, ioctl() is completely devoid of compile-time type checking; therefore, it can be a source of bugs that are difficult to track down.
Consider two ioctl() calls—one that manipulates a pointer to a 32-bit quantity (IOP32), the other that manipulates a pointer to a long quantity (IOPLONG).
The following code sample works as part of a 32-bit application:
int a, d; long b; ... if (ioctl(d, IOP32, &b) == -1) return (errno); if (ioctl(d, IOPLONG, &a) == -1) return (errno);
Both ioctl(2) calls work correctly when this code fragment is compiled and run as part of a 32-bit application.
Both ioctl() calls also return success when this code fragment is compiled and run as a 64-bit application. However, neither ioctl() works correctly. The first ioctl() passes a container that is too big, and on a big-endian implementation, the kernel will copy in or copy out from the wrong part of the 64-bit word. Even on a little-endian implementation, the container probably contains stack garbage in the upper 32-bits. The second ioctl() will copy in or copy out too much, either reading an incorrect value, or corrupting adjacent variables on the user stack.