Bug 11106 - asm-generic/ioctl.h can generate link error undefined __invalid_size_argument_for_IOC
Summary: asm-generic/ioctl.h can generate link error undefined __invalid_size_argument...
Status: RESOLVED CODE_FIX
Alias: None
Product: IO/Storage
Classification: Unclassified
Component: Other (show other bugs)
Hardware: All Linux
: P1 low
Assignee: David Woodhouse
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-07-16 20:58 UTC by Bob Arendt
Modified: 2008-12-01 07:18 UTC (History)
0 users

See Also:
Kernel Version: linux/kernel/git/stable/linux-2.6.25.y.git (using 2.6.25.10)
Subsystem:
Regression: ---
Bisected commit-id:


Attachments

Description Bob Arendt 2008-07-16 20:58:42 UTC
Summary:
This is an exported API file (in kernel-headers for rpm-based distros).
A compile-time test has unintended behaviour depending on user compiler.

This issue appears to have been introduced with:

http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.25.y.git;a=commit;h=af4cd3fe4cfa75ca74f8d8622867371289043a8d

This patch distilled various includes into the current include/asm-generic/ioctl.h

Hardware Environment:
using i386 / x86_64 platforms (should be platform independent)

Software Environment:
Intel compiler 10.1.15 building user program with user-defined ioctl() calls.

Problem Description:
Building a program with debug (-g flag) can result in undefined reference to "__invalid_size_argument_for_IOC".

This code from include/asm-generic/ioctl.h is the culprit:
     50 /* provoke compile error for invalid uses of size argument */
     51 extern unsigned int __invalid_size_argument_for_IOC;
     52 #define _IOC_TYPECHECK(t) \
     53         ((sizeof(t) == sizeof(t[1]) && \
     54           sizeof(t) < (1 << _IOC_SIZEBITS)) ? \
     55           sizeof(t) : __invalid_size_argument_for_IOC)
     ....
     61 #define _IOWR(type,nr,size)     _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

This gets used in the various _IO definitions.  The comment indicates this was intended to throw a compiler error.  It doesn't - it will always compile and end up generating a link-error for an undefined reference to __invalid_size_argument_for_IOC.

In fact, lines 51-55 will only work *if* the compiler always optimizes away the reference to __invalid_size_argument_for_IOC.  It turns out that gcc (currently) actually does optimize this out in all cases (even -g -O0), and never generates the undefined link reference.

This isn't true for Intel's compilers (icc and icpc).  If the -g flag is asserted the reference is generated and the error *always* occurs.  It's hard to generate a debug image;  The work-around hack is ugly - add a global def for __invalid_size_argument_for_IOC.  This also disables the test.  The intel compiler might not be the only one that has this behaviour.

This fragment should be modified to generate an actual compile-time error, rather than an undefined linkage.  I'm also going to give a heads-up to the intel compiler folks.  Thanks for considering this.


Steps to reproduce:
Here's a short program:

// Build with:
//   (OK)      gcc    -Wall ioctl_broke.c
//   (OK)      gcc -g -Wall ioctl_broke.c
//   (OK)      icc    -Wall ioctl_broke.c
//   (Breaks)  icc -g -Wall ioctl_broke.c
//             /tmp/iccRFH4Pa.o: In function `main':
//             /home/rda/ioctl_test.c:23: undefined reference to `__invalid_size_argument_for_IOC'
//

#include <string.h>
#include <inttypes.h>
#include <sys/ioctl.h>

typedef struct my_ioctl {
  int32_t	function, offset;
  void *	bufaddr;
  int32_t	bytes, status;
} MYIOCTL;

int main ( int argc, char *argv[] )
{
  MYIOCTL myio;
  ioctl ( 6, _IOWR('f',0x1, MYIOCTL), &myio );
  return 0;
}
Comment 1 David Woodhouse 2008-09-24 09:56:05 UTC
Fixed by commit 5f8c3c8edff426fd87098f057688463107fcd9ce
Comment 2 juergen.gohlke 2008-12-01 06:19:11 UTC
When the ioctl command defined with _IOR etc. is used in a case statement, gcc (version 3.4.6) generates a compile time error: `__invalid_size_argument_for_IOC' cannot appear in a constant expression

code example:
#include <sys/ioctl.h>
#define AQ_VERSION _IOR(0xa1, 0x14, int)
...
switch (ioccmd) {
case AQ_VERSION: ...;
}
Comment 3 David Woodhouse 2008-12-01 06:28:01 UTC
This was fixed by commit 5f8c3c8edff426fd87098f057688463107fcd9ce. It sounds like you're using old or broken kernel headers. In /usr/include/asm-generic/ioctl.h, the macro _IOC_TYPECHECK should be unconditionally defined as follows:

#define _IOC_TYPECHECK(t) (sizeof(t))

If your distribution is not using the headers generated by running 'make headers_install' against a recent kernel, please file a bug against your distribution.
Comment 4 Bob Arendt 2008-12-01 07:18:14 UTC
I can confirm that this commit shows up in Fedora 10.
But it does not in Redhat 5.2 (I'll file a bug)

Note You need to log in before you can comment on or make changes to this bug.