Path: csiph.com!eternal-september.org!feeder.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: Function pointers conversions and UB Date: Wed, 11 Jan 2017 13:51:32 -0800 Organization: None to speak of Lines: 64 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: mx02.eternal-september.org; posting-host="773e6a95afbb07ee2983b9f78b62bfd0"; logging-data="5289"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+5M4EcN2Pkw+i5mOHlry7h" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) Cancel-Lock: sha1:k2u2L4YzQQbf/woG2RE1bizuc1w= sha1:V4iwiqbLscobSEVtMg3bFV6Z50M= Xref: csiph.com comp.lang.c:101470 Noob writes: > Hello, > > 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? It violates a constraint. There is no implicit conversion from one pointer-to-function type to another. > 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." Yes, it "may be converted", but a cast is required. This is valid and exhibits no undefined behavior: void foo(struct s *arg) { } void (*fp)(void *) = (void(*)(void*))foo; (Presumably `struct s` is defined somewhere; otherwise it's not visible outside the function definition, and it's going to be difficult to write a meaningful call.) > So the following code does have UB, correct? > > void foo(struct s *arg) { } > void (*fp)(void *) = foo; Again, assume a cast. > void bar(void) { fp(); } /* nasal demons from fp() */ Actually that's another constraint violation -- but fp(NULL); is legal (doesn't violate a syntax rule or constraint) and has undefined behavior. > 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? > > I lack imagination... What else? Pointer representation/encoding? A likely cause of the call not "working as expected" (which actually depends a great deal on your expectations) is that you've passed a pointer to an object that isn't properly aligned to point to a `struct s` object. Differing representations and argument passing conventions are also possibilities (likely not to apply to most current systems). And compiler optimization could mess things up. -- Keith Thompson (The_Other_Keith) kst-u@mib.org Working, but not speaking, for JetHead Development, Inc. "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"