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".

Reply via email to