Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.93k stars 551 forks source link

Fix for Configure's csym test for gcc's link time optimisation breaks detection of data pointers #11598

Closed p5pRT closed 13 years ago

p5pRT commented 13 years ago

Migrated from rt.perl.org#97672 (status was 'resolved')

Searchable as RT97672$

p5pRT commented 13 years ago

From @nwc10

Created by @nwc10

This commit

commit e820c6d6a6d0a8828aa68a6895696b659c471f2f Author​: H.Merijn Brand \h\.m\.brand@​xs4all\.nl Date​: Mon Aug 22 15​:41​:26 2011 +0200

  Fix Configure's csym test for gcc's link time optimisation  
  This introduces a volatile into the test program so gcc cannot optimise   out the symbol itself as being unused.

has the unfortunate side effect of breaking detection of non-function pointers​:

$ diff -u config.sh ../config.sh.after

Inline Patch ```diff --- config.sh 2011-08-24 17:52:07.000000000 +0200 +++ ../config.sh.after 2011-08-24 17:43:30.000000000 +0200 @@ -8,7 +8,7 @@ # Package name : perl5 # Source directory : . -# Configuration time: Wed Aug 24 17:51:18 CEST 2011 +# Configuration time: Wed Aug 24 17:42:35 CEST 2011 # Configured by : nick # Target system : linux gcc10 2.6.32-bpo.5-amd64 #1 smp fri jun 11 08:42:31 utc 2010 x86_64 gnulinux @@ -73,7 +73,7 @@ ccversion='' cf_by='nick' cf_email='nick@gcc10.fsffrance.org' -cf_time='Wed Aug 24 17:51:18 CEST 2011' +cf_time='Wed Aug 24 17:42:35 CEST 2011' charbits='8' charsize='1' chgrp='' @@ -508,7 +508,7 @@ d_syscallproto='define' d_sysconf='define' d_sysernlst='' -d_syserrlst='define' +d_syserrlst='undef' d_system='define' d_tcgetpgrp='define' d_tcsetpgrp='define' @@ -522,7 +522,7 @@ d_tmpnam_r='undef' d_truncate='define' d_ttyname_r='undef' -d_tzname='define' +d_tzname='undef' d_u32align='define' d_ualarm='define' d_umask='define' ```

and

$ diff -u config.sh.gcc.{before\,after}

Inline Patch ```diff --- config.sh.gcc.before 2011-08-24 16:32:00.000000000 +0200 +++ config.sh.gcc.after 2011-08-24 15:07:45.000000000 +0200 @@ -8,7 +8,7 @@ # Package name : perl5 # Source directory : . -# Configuration time: Wed Aug 24 16:31:11 CEST 2011 +# Configuration time: Wed Aug 24 15:06:46 CEST 2011 # Configured by : nick # Target system : darwin mouse-mill.local 10.8.0 darwin kernel version 10.8.0: tue jun 7 16:33:36 pdt 2011; root:xnu-1504.15.3~1release_i386 i386 @@ -97,7 +97,7 @@ ccversion='' cf_by='nick' cf_email='nick@ccl4.org' -cf_time='Wed Aug 24 16:31:11 CEST 2011' +cf_time='Wed Aug 24 15:06:46 CEST 2011' charbits='8' charsize='1' chgrp='' @@ -532,7 +532,7 @@ d_syscallproto='define' d_sysconf='define' d_sysernlst='' -d_syserrlst='define' +d_syserrlst='undef' d_system='define' d_tcgetpgrp='define' d_tcsetpgrp='define' @@ -546,7 +546,7 @@ d_tmpnam_r='undef' d_truncate='define' d_ttyname_r='define' -d_tzname='define' +d_tzname='undef' d_u32align='define' d_ualarm='define' d_umask='define' ```

Strangely, no tests fail on Linux, whereas on OS X*, I see this:

$ ./perl -MTestInit ext/POSIX/t/time.t 1..13 not ok 1 - tzset() to GMT/UTC # Failed test 'tzset() to GMT/UTC' # at ext/POSIX/t/time.t line 24. # '' # doesn't match '(?^i​:(GMT|UTC))'ok 2 # skip Mac OS X/Darwin doesn't handle this ok 3 - asctime() and ctime() at zero ok 4 - asctime() and ctime() at 12345678 ok 5 - get ctime() equal to strftime() ok 6 - strftime() can handle unicode chars in the format string ok 7 - Not internally UTF-8 encoded ok 8 - Format string has correct character ok 9 - Still not internally UTF-8 encoded ok 10 - clock() returns a numeric value ok 11 - ...and it returns something >= 0 ok 12 - difftime() ok 13 - mktime() # Looks like you failed 1 test of 13.

[it happens that both machines are currently in CEST]

The test C program for function pointers looks like this​:

$ cat /tmp/try-\(\).c volatile int dummy = 0; extern void *tcsetattr(); void *(*(p()))() { return dummy + &tcsetattr; } int main() { if(p()) return(0); else return(1); }

The test C program for data pointers looks like this​:

$ cat /tmp/try-\[\].c volatile int dummy = 0; extern void *tzname[]; void *(*(p()))[] { return dummy + &tzname; } int main() { if(p()) return(0); else return(1); }

gcc and clang both fault this​:

$ cat /tmp/try-\[\].c volatile int dummy = 0; extern void *tzname[]; void *(*(p()))[] { return dummy + &tzname; } int main() { if(p()) return(0); else return(1); } $ gcc /tmp/try-\[\].c /tmp/try-[].c​: In function 'p'​: /tmp/try-[].c​:1​: error​: invalid use of array with unspecified bounds nick@​mouse-mill [1]$ clang /tmp/try-\[\].c /tmp/try-[].c​:1​:80​: error​: arithmetic on pointer to incomplete type   'void *(*)[]'   ...*tzname[]; void *(*(p()))[] { return dummy + &tzname; } int main() { ...   ^ ~~~ 1 error generated.

[what you can't see in this plain-text e-mail is how clang puts the error message in bold\, the word error in red\, and the pointer to the problem in green.]

I don't know what the correct fix should be.

I also don't understand why Linux isn't now failing tests\, as it clearly now fails to detect the two symbols in question.

Nicholas Clark

* We play both kinds of operating system\, Linux and OS X :-)

Perl Info ``` Flags: category=core severity=high Site configuration information for perl 5.15.2: Configured by nick at Wed Aug 24 17:29:07 CEST 2011. Summary of my perl5 (revision 5 version 15 subversion 2) configuration: Derived from: e820c6d6a6d0a8828aa68a6895696b659c471f2f Platform: osname=darwin, osvers=10.8.0, archname=darwin-thread-multi-2level uname='darwin mouse-mill.local 10.8.0 darwin kernel version 10.8.0: tue jun 7 16:33:36 pdt 2011; root:xnu-1504.15.3~1release_i386 i386 ' config_args='-Dusedevel=y -Dcc=ccache gcc -Dld=gcc -Ubincompat5005 -Uinstallusrbinperl -Dcf_email=nick@ccl4.org -Dperladmin=nick@ccl4.org -Dinc_version_list= -Dinc_version_list_init=0 -Dstatic_ext=Fcntl -DDEBUGGING -Doptimize=-g -Dusethreads -Uuse64bitall -Uuselongdouble -Uusemymalloc -Duseperlio -Dprefix=~/Sandpit/snap5.9.x-v5.15.2-25-ge820c6d-i -Dinstallman1dir=none -Dinstallman3dir=none -Dusevendorprefix -Dvendorprefix=~/Sandpit/vendor -Uuserelocatableinc -Ud_dosuid -Uuseshrplib -de -Accccflags=-fcatch-undefined-behavior -Accccflags=-DNO_PERL_PRESERVE_IVUV -Umad' hint=recommended, useposix=true, d_sigaction=define useithreads=define, usemultiplicity=define useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef use64bitint=define, use64bitall=undef, uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='ccache gcc', ccflags ='-fno-common -DPERL_DARWIN -no-cpp-precomp -DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector -I/opt/local/include', optimize='-g', cppflags='-no-cpp-precomp -fno-common -DPERL_DARWIN -no-cpp-precomp -DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector -I/opt/local/include' ccversion='', gccversion='4.2.1 (Apple Inc. build 5666) (dot 3)', gccosandvers='' intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16 ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8 alignbytes=8, prototype=define Linker and Libraries: ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags =' -fstack-protector -L/usr/local/lib -L/opt/local/lib' libpth=/usr/local/lib /opt/local/lib /usr/lib libs=-lgdbm -ldbm -ldl -lm -lutil -lc perllibs=-ldl -lm -lutil -lc libc=, so=dylib, useshrplib=false, libperl=libperl.a gnulibc_version='' Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' ' cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup -L/usr/local/lib -L/opt/local/lib -fstack-protector' Locally applied patches: @INC for perl 5.15.2: lib /Users/nick/Sandpit/snap5.9.x-v5.15.2-25-ge820c6d-i/lib/perl5/site_perl/5.15.2/darwin-thread-multi-2level /Users/nick/Sandpit/snap5.9.x-v5.15.2-25-ge820c6d-i/lib/perl5/site_perl/5.15.2 /Users/nick/Sandpit/vendor/lib/perl5/vendor_perl/5.15.2/darwin-thread-multi-2level /Users/nick/Sandpit/vendor/lib/perl5/vendor_perl/5.15.2 /Users/nick/Sandpit/snap5.9.x-v5.15.2-25-ge820c6d-i/lib/perl5/5.15.2/darwin-thread-multi-2level /Users/nick/Sandpit/snap5.9.x-v5.15.2-25-ge820c6d-i/lib/perl5/5.15.2 . Environment for perl 5.15.2: DYLD_LIBRARY_PATH (unset) HOME=/Users/nick LANG=en_GB.ISO8859-1 LANGUAGE (unset) LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/opt/local/bin:/opt/local/sbin:/Users/nick/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/usr/local/sbin:/sbin:/usr/sbin PERL_BADLANG (unset) SHELL=/bin/bash ```
p5pRT commented 13 years ago

From @nwc10

On Wed\, Aug 24\, 2011 at 09​:09​:31AM -0700\, Nicholas Clark wrote​:

The test C program for function pointers looks like this​:

$ cat /tmp/try-\(\).c volatile int dummy = 0; extern void *tcsetattr(); void *(*(p()))() { return dummy + &tcsetattr; } int main() { if(p()) return(0); else return(1); }

The test C program for data pointers looks like this​:

$ cat /tmp/try-\[\].c volatile int dummy = 0; extern void *tzname[]; void *(*(p()))[] { return dummy + &tzname; } int main() { if(p()) return(0); else return(1); }

There's a lot of explanation of why it looks like that in a thread from 2003\, particularly this message​: http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2003-06/msg00358.html

and a reference to gcc 3.4 being a problem in this subsequent commit​:

commit 373dfab3839ca168fd2249c0b2b694722e478652 Author​: Jarkko Hietaniemi \jhi@​iki\.fi Date​: Thu Sep 18 04​:54​:16 2003 +0000

  Patch from Enache Adrian for the new tricks of gcc 3.4   for "is this symbol defined" scanning of Configure.  
  p4raw-id​: //depot/perl@​21267

but I don't know *why* gcc 3.4 was a problem.

I'm wondering if the printf() approach (or something like it) is actually sane to use for pointers-to-data. The hoop jumping seems mostly to be about pointers-to-functions. (Avoiding crashes\, compilers choking\, and compilers optimising everything away)

Or if it's sane to change [] to [1]. Or dummy + &tzname to dummy + tzname. (As the latter is not trying to do arithmetic on a pointer to an incomplete type)

Nicholas Clark

p5pRT commented 13 years ago

From @nwc10

On Wed\, Aug 24\, 2011 at 07​:09​:25PM +0100\, Nicholas Clark wrote​:

Or if it's sane to change [] to [1]. Or dummy + &tzname to dummy + tzname. (As the latter is not trying to do arithmetic on a pointer to an incomplete type)

The latter seems to work. Something like this​:

Inline Patch ```diff diff --git a/Configure b/Configure index d4c95a7..9eee523 100755 --- a/Configure +++ b/Configure @@ -7754,9 +7754,9 @@ eval $setvar : is a C symbol defined? csym='tlook=$1; case "$3" in --v) tf=libc.tmp; tdc="";; --a) tf=libc.tmp; tdc="[]";; -*) tlook="^$1\$"; tf=libc.list; tdc="()";; +-v) tf=libc.tmp; tdc=""; deref="&";; +-a) tf=libc.tmp; tdc="[]"; deref="";; +*) tlook="^$1\$"; tf=libc.list; tdc="()"; deref="&";; esac; case "$d_cplusplus" in $define) extern_C="extern \"C\"" ;; @@ -7774,13 +7774,13 @@ yes) if $contains $tlook $tf >/dev/null 2>&1; then tval=true; elif $test "$mistrustnm" = compile -o "$mistrustnm" = run; then - echo "volatile int dummy = 0; $extern_C void *$1$tdc; void *(*(p()))$tdc { return dummy + &$1; } int main() { if(p()) return(0); else return(1); }"> try.c; + echo "volatile int dummy = 0; $extern_C void *$1$tdc; void *(*(p()))$tdc { return dummy + $deref$1; } int main() { if(p()) return(0); else return(1); }"> try.c; $cc -o try $optimize $ccflags $ldflags try.c >/dev/null 2>&1 $libs && tval=true; $test "$mistrustnm" = run -a -x try && { $run ./try$_exe >/dev/null 2>&1 || tval=false; }; $rm_try; fi; else - echo "volatile int dummy = 0; $extern_C void *$1$tdc; void *(*(p()))$tdc { return dummy + &$1; } int main() { if(p()) return(0); else return(1); }"> try.c; + echo "volatile int dummy = 0; $extern_C void *$1$tdc; void *(*(p()))$tdc { return dummy + $deref$1; } int main() { if(p()) return(0); else return(1); }"> try.c; $cc -o try $optimize $ccflags $ldflags try.c $libs >/dev/null 2>&1 && tval=true; $rm_try; fi; ```

Not "very" tested. (Works on OS X, works on g++ on Linux. That's all I know)

Nicholas Clark

p5pRT commented 13 years ago

From @craigberry

On Wed\, Aug 24\, 2011 at 3​:05 PM\, Nicholas Clark \nick@​ccl4\.org wrote​:

On Wed\, Aug 24\, 2011 at 07​:09​:25PM +0100\, Nicholas Clark wrote​:

Or if it's sane to change [] to [1]. Or dummy + &tzname to dummy + tzname. (As the latter is not trying to do arithmetic on a pointer to an incomplete type)

The latter seems to work. Something like this​:

diff --git a/Configure b/Configure index d4c95a7..9eee523 100755 --- a/Configure +++ b/Configure @​@​ -7754\,9 +7754\,9 @​@​ eval $setvar  : is a C symbol defined?  csym='tlook=$1;  case "$3" in --v) tf=libc.tmp; tdc="";; --a) tf=libc.tmp; tdc="[]";; -*) tlook="^$1\$"; tf=libc.list; tdc="()";; +-v) tf=libc.tmp; tdc=""; deref="&";; +-a) tf=libc.tmp; tdc="[]"; deref="";; +*) tlook="^$1\$"; tf=libc.list; tdc="()"; deref="&";;  esac;  case "$d_cplusplus" in     $define)   extern_C="extern \"C\"" ;; @​@​ -7774\,13 +7774\,13 @​@​ yes)                if $contains $tlook $tf >/dev/null 2>&1; then                        tval=true;                elif $test "$mistrustnm" = compile -o "$mistrustnm" = run; then -                       echo "volatile int dummy = 0; $extern_C void *$1$tdc; void *(*(p()))$tdc { return dummy + &$1; } int main() { if(p()) return(0); else return(1); }"> try.c; +                       echo "volatile int dummy = 0; $extern_C void *$1$tdc; void *(*(p()))$tdc { return dummy + $deref$1; } int main() { if(p()) return(0); else return(1); }"> try.c;                        $cc -o try $optimize $ccflags $ldflags try.c >/dev/null 2>&1 $libs && tval=true;                        $test "$mistrustnm" = run -a -x try && { $run ./try$_exe >/dev/null 2>&1 || tval=false; };                        $rm_try;                fi;        else -               echo "volatile int dummy = 0; $extern_C void *$1$tdc; void *(*(p()))$tdc { return dummy + &$1; } int main() { if(p()) return(0); else return(1); }"> try.c; +               echo "volatile int dummy = 0; $extern_C void *$1$tdc; void *(*(p()))$tdc { return dummy + $deref$1; } int main() { if(p()) return(0); else return(1); }"> try.c;                $cc -o try $optimize $ccflags $ldflags try.c $libs >/dev/null 2>&1 && tval=true;                $rm_try;        fi;

Not "very" tested. (Works on OS X\, works on g++ on Linux. That's all I know)

If I understand this right\, you're just making the "&" go away for the case where the symbol being checked is not a function. There's more to the story\, though\, in that even for function pointers\, that try.c code (before your change) does not compile\, at least not for​:

% g++ -v Using built-in specs. Target​: i686-apple-darwin10 Configured with​: /var/tmp/gcc/gcc-5666.3~6/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c\,objc\,c++\,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 Thread model​: posix gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)

I somewhat clumsily reported more details here​:

http​://www.nntp.perl.org/group/perl.perl5.porters/2011/08/msg176278.html

before bothering to look up how pointers work in C++ (incrementing objects\, not memory locations). It looks like trying to do pointer arithmetic with function pointers in C++ is just wrong\, so I don't see the whole "volatile int dummy" approach being viable in its current form.

The following compiles on a couple of different C++ compilers​:

% cat try3.c extern "C" volatile void *memchr(); volatile void *(*(p()))() { return &memchr; } int main() { if(p()) return(0); else return(1); }

and C as well after removing the C\<"C">. But I have no idea what making the function pointer itself volatile does for the original problem\, i.e. something getting optimized away for some version of gcc (what version?\, and was it actually ld\, since the commit message says link-time optimization?).

p5pRT commented 13 years ago

The RT System itself - Status changed from 'new' to 'open'

p5pRT commented 13 years ago

From @nwc10

On Fri\, Aug 26\, 2011 at 01​:39​:10AM -0500\, Craig A. Berry wrote​:

If I understand this right\, you're just making the "&" go away for the case where the symbol being checked is not a function. There's more

Yes\, well\, specifically "an array". The Configure code also has a case for neither-a-function-nor-and-array. I'm not sure why the distinction between the two not-a-function things is needed\, but it seems that there are a lot of corner cases here.

. Neither gcc (4.2 I think) and clang compile

to the story\, though\, in that even for function pointers\, that try.c code (before your change) does not compile\, at least not for​:

% g++ -v Using built-in specs. Target​: i686-apple-darwin10 Configured with​: /var/tmp/gcc/gcc-5666.3~6/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c\,objc\,c++\,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 Thread model​: posix gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)

I somewhat clumsily reported more details here​:

http​://www.nntp.perl.org/group/perl.perl5.porters/2011/08/msg176278.html

before bothering to look up how pointers work in C++ (incrementing objects\, not memory locations). It looks like trying to do pointer arithmetic with function pointers in C++ is just wrong\, so I don't see the whole "volatile int dummy" approach being viable in its current form.

Hmm yes\, that makes sense\, sadly.

The following compiles on a couple of different C++ compilers​:

% cat try3.c extern "C" volatile void *memchr(); volatile void *(*(p()))() { return &memchr; } int main() { if(p()) return(0); else return(1); }

and C as well after removing the C\<"C">. But I have no idea what making the function pointer itself volatile does for the original problem\, i.e. something getting optimized away for some version of gcc (what version?\, and was it actually ld\, since the commit message says link-time optimization?).

I have no idea either.

Another trick would be to have a union between the function pointer and a void *\, assign the function pointer to the union\, and do arithmetic with the volatile 0 and the void * in the union. (Not tested\, but I know that perl.h had to do this to keep Crays happy\, because their compiler wanted to enforce the rules about not casting between function and data pointers)

Nicholas Clark

p5pRT commented 13 years ago

From @cpansprout

H.Merijn Brand has reverted the change\, with commit 9945eb56\, so I’m marking this as resolved (at least for now).

p5pRT commented 13 years ago

@cpansprout - Status changed from 'open' to 'resolved'

p5pRT commented 13 years ago

From @paulg1973

This is not in response to any particular comment in this thread\, so I have deleted the message history. It is a general command on how the ANSI/ISO C Standard handles function pointers. I think it is relevant to this discussion; I think I can explain why pointers to functions are "special".

The C standard places many restrictions on pointers to functions. The motivation for this is that in some implementations a pointer to a function also requires one or more additional pointers to be provided at the same time. Typically\, the extra pointer would point to the static data for the function. For this reason\, the C Standard permits an implementation to create function pointers that are of a different size than pointers to other objects. It goes to some trouble to hide the size of a function pointer. A standards-conforming program is not permitted to use the sizeof operator on a pointer to a function (see 6.3.3.4 in the C89 std). A pointer to void can be assigned to a pointer to a function (6.2.2.3)\, and pointers to one function can be cast to pointers to other functions (6.3.4)\, but the standard explicitly rules out converting a pointer to a function to a pointer to a (different) object\, or vice versa (G.2\, referencing 6.3.4).

It is certainly true that many implementations arrange for pointers to functions to occupy the same number of bits as pointers to objects. But the language doesn't require this. (In our implementation here\, pointers to functions actually point to a pair of pointers\, which are the real pointers that are actually used to invoke a function\, just to satisfy programs that don't obey the standard's rules).

Doing pointer arithmetic on pointers to functions isn't allowed by the C89 standard\, either.

I agree with Alan Burlison's comment in http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2003-06/msg00358. html that "To be absolutely sure the symbol exists\, it is necessary to actually run the test executable." Just compiling and linking a program and checking for a successful compilation is insufficient. Many linkers consider it to be a non-fatal error to reference an undefined name; these implementations defer the checks until the name is referenced at execution time. Even when you run the program\, it is valid under older versions of the POSIX standard for a function to return ENOSYS\, which tells you that the function exists but is not implemented. All of these cases apply in our implementation; thankfully\, we do provide the appropriate "__stub_xxx" macro in features.h to indicate which functions exist but happen to be dummies\, so it is not necessary to test for ENOSYS.

I don't see how fussing with the volatile attribute is interesting or useful. And playing with unions of function pointers and non-function pointers is diving down into implementation details that you should really avoid at all costs.

My advice is to stay well within the confines of the normal language rules. The KISS principle applies in spades here. The C standard allows for a limited mismatch of function declarations (one can ask for the address of a function using the wrong declaration\, for example. You just can't invoke the function using the wrong declaration). This is how the autoconf macros are able to have a single template source file test for the existence of a wide variety of POSIX functions.

Again\, I hope these remarks are helpful. If you already know this stuff\, I apologize for the unnecessary lecture.

Thanks PG -- Sr. Technical Consultant\, Stratus Technologies Inc. Work​: +1-978-461-7557; FAX​: +1-978-461-3610; Twitter​: stratuspaulg

p5pRT commented 13 years ago

From @tonycoz

On Fri\, Aug 26\, 2011 at 12​:57​:44PM -0400\, Green\, Paul wrote​:

The C standard places many restrictions on pointers to functions. The motivation for this is that in some implementations a pointer to a function also requires one or more additional pointers to be provided at the same time. Typically\, the extra pointer would point to the static data for the function.

There was (is?) one platform that was very common when C89 was being written where the size of a function pointers and data pointers could simply be different sizes - 16-bit code on DOS (or Win16).

For this reason\, the C Standard permits an implementation to create function pointers that are of a different size than pointers to other objects. It goes to some trouble to hide the size of a function pointer. A standards-conforming program is not permitted to use the sizeof operator on a pointer to a function (see 6.3.3.4 in the C89 std). ...

This is incorrect.

It's true you're not permitted to use sizeof() on a function itself ("an expression with function type")\, but there's no problem calling sizeof on a pointer to a function.

If you're thinking of the automatic conversion of function types to pointer to function type\, that doesn't occur in the context of sizeof(). (C89 6.2.2.1)

Tony