http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59905
Bug ID: 59905 Summary: Unfriendly abort when calling a fucntion via a function pointer cast Product: gcc Version: 4.7.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: nisse at lysator dot liu.se Created attachment 31918 --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=31918&action=edit Example program Some background: In GNU nettle, I use function casts between function types differing in the type of some pointer arguments. E.g., struct s; int foo(struct s *); typedef int func_t(void *); func_t *f = (func_t *) foo; Later on, f will be called with an argument of type void *, which actually is a pointer to a valid struct s, but cast to void *. I'm aware this is not strictly valid C, but I expect it to work on virtually all C implementations, because struct s may well be an incomplete type, and hence the calling conventions cannot reasonably depend on it's actual definition. If it matters, I could replace void * above by struct anything *, where struct anything is a different incomplete type, not defined in any compilation unit ever. (If you know any examples of architectures, supported by gcc or otherwise, where calling conventions make this break, I'd be curious to know about it). And I think this style is fairly common in object oriented C code. The closest alternatives, if one wants to stick to the C specification, is to either skip type checking altogether, always using void * for the function arguments, and casting when used. Or have do-nothing wrapper functions like int foo(struct s *); int foo_wrapper(void *p) { return foo(p); } This would typically compile to a single jump instruction, but I don't think the wrapper can be eliminated completely by an optimizing C compiler, because it is required that pointer comparison foo == foo_wrapper gives a false result. And the reason I care is that I have a library with fairly a large number of functions, which I want to let applications call either directly, *with* strong type checking of all arguments, or call via an abstraction using function pointers and void * instead of the real struct type pointer, for state/context arguments. This style seems to work fine with gcc. The surprise is when you call a function via a cast like this, *without* first storing it a variable. Like struct s; ((func_t *)foo)(&s); Here, the compiler issues a warning, and replaces the call by a call to abort(). I'm attaching a complete example program. With gcc-4.7.2, on Debian GNU/linux x86_64, this is what happens (and it's the same with gcc-4.4 and gcc-4.6) $ gcc func-cast.c func-cast.c: In function ‘main’: func-cast.c:33:41: warning: function called through a non-compatible type [enabled by default] func-cast.c:33:41: note: if this code is reached, the program will abort $ ./a.out foo x: 1 bar x (var): 2 Illegal instruction (core dumped) I find this behaviour a bit obnoxious... I understand you might just say that this is bad code and gcc could emit an exec("nethack") if it wanted to. I think the current gcc behaviour is bad, in particular as default behavior, because 1. Generating a call to abort is generally unfriendly. 2. I expect that f = expr; f(...); and (expr)(...); should behave in roughly the same way for all possible expr, at least as long as f and expr have the same type, so the assignment itself doesn't imply any type conversion. 3. I think the compiler should in general treat explicit casts in the source code as meaning "I think I know what I'm doing, please don't complain about it".