Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #101468

Re: Function pointers conversions and UB

From jt@toerring.de (Jens Thoms Toerring)
Newsgroups comp.lang.c
Subject Re: Function pointers conversions and UB
Date 2017-01-11 21:46 +0000
Organization Freie Universitaet Berlin
Message-ID <ednnehFgetrU1@mid.uni-berlin.de> (permalink)
References <o564ak$fjf$1@dont-email.me>

Show all headers | View raw


Noob <root@127.0.0.1> wrote:
> Consider the following code:

> void foo(struct s *arg) { }
> void (*fp)(void *) = foo;

> As far as I understand, this does /not/ have UB, because fp is not used
> to call the function. Is that correct?

> C99 6.3.2.3 p8
> "A pointer to a function of one type may be converted to a pointer to a
> function of another type and back again; the result shall compare equal to
> the original pointer. If a converted pointer is used to call a function
> whose type is not compatible with the pointed-to type, the behavior is
> undefined."

> So the following code does have UB, correct?

> void foo(struct s *arg) { }
> void (*fp)(void *) = foo;
> void bar(void) { fp(); } /* nasal demons from fp() */

This call probaly will get the compiler to complain since
you call via 'fp' without an argument eventhough 'fp' is
defined to point to a function that expects one (regard-
less of if it's the wrong type). I assume you forgot e.g.
a 'NULL' argument here.

> I assume the behavior will be "it works as expected" on most platforms.
> How/where will it blow up?

> Platforms with different argument passing for void * and other pointers?

Indeed. A platform definitely may have pointers of different
sizes, where void pointers, of course, must be large enough
to represent pointers of all possible sizes. One, though pu-
rely theoretical, problem might be an architecture with dedi-
cated registers for e.g. small and large pointers. Given a
calling convention that allows for passing arguments via re-
gisters (which is very common), in that case the argument you
call the function via 'fp' with might be passed via a register
for 'long' pointers, but the function expects it in a register
for a 'short' pointer, thus getting some garbage. Or, if 'small'
pointers have just half the size of a 'large' pointer, it may
try to pass two 'small' pointers combined into a register for
a 'large' pointer, shifting one of them to the more signifi-
cant bits. If the calling convention calls for the first poin-
ter passed to always be shifted up (even if there's only one),
the function called will only use the upper half of the regis-
ter, but which, due to being called with a 'long' pointer, con-
tains the "relevant" bits in the lower half.

This is indeed purely theoretical (at least I don't know of
any such architecture), but that kind of problem isn't unknown
on archtiectures with dedicated data and address registers when
you try to use e.g. ints (or longs, whatever fits the size of a
pointer) instead of a pointer. If you'd do something like this

void foo(void *);
void (*fp)(int) = foo;
...
fp(0x1000);

(where 0x1000 might be a perfectly valid address for the
purposes of foo()) the compiler may pass the argument via
a data register while the actual function called may look
for it in an address register - which just contains some
more or less random value.

On that kind of architecture it's also a not too uncommon (and
hard to spot) bug when you have e.g.

/* no include of <stdlib.h> */

int *ip = (int *) malloc(100 * sizeof *ip);

malloc() will return via a address register, but since
there's no declaration of malloc() the compiler assumes
that it returns an int (at least with C89). And thus in
the caller an attempt will be made to retrieve the return
value from a data register and use that (random) value for
'ip' - with the somewhat unintuitive result that the return
value looks like malloc() succeeded (it's not necessarily
NULL), but an attempt to use 'ip' is rather likely to pro-
duce a segmentation fault.

                      Best regards, Jens
-- 
  \   Jens Thoms Toerring  ___      jt@toerring.de
   \__________________________      http://toerring.de

Back to comp.lang.c | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Function pointers conversions and UB Noob <root@127.0.0.1> - 2017-01-11 21:26 +0100
  Re: Function pointers conversions and UB "James R. Kuyper" <jameskuyper@verizon.net> - 2017-01-11 15:57 -0500
    Re: Function pointers conversions and UB supercat@casperkitty.com - 2017-01-11 14:37 -0800
  Re: Function pointers conversions and UB jt@toerring.de (Jens Thoms Toerring) - 2017-01-11 21:46 +0000
  Re: Function pointers conversions and UB Keith Thompson <kst-u@mib.org> - 2017-01-11 13:51 -0800
    Re: Function pointers conversions and UB "James R. Kuyper" <jameskuyper@verizon.net> - 2017-01-11 17:06 -0500
  Re: Function pointers conversions and UB Noob <root@127.0.0.1> - 2017-01-12 00:29 +0100
    Re: Function pointers conversions and UB Richard Heathfield <rjh@cpax.org.uk> - 2017-01-11 23:37 +0000
      Re: Function pointers conversions and UB supercat@casperkitty.com - 2017-01-11 21:49 -0800
        Re: Function pointers conversions and UB Richard Heathfield <rjh@cpax.org.uk> - 2017-01-12 09:41 +0000
      Re: Function pointers conversions and UB Noob <root@127.0.0.1> - 2017-01-12 10:52 +0100
        Re: Function pointers conversions and UB Richard Heathfield <rjh@cpax.org.uk> - 2017-01-12 09:58 +0000
  Re: Function pointers conversions and UB Noob <root@127.0.0.1> - 2017-01-12 13:08 +0100
    Re: Function pointers conversions and UB Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-01-12 13:45 +0000

csiph-web