Closed p5pRT closed 13 years ago
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
and
$ diff -u config.sh.gcc.{before\,after}
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 :-)
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
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:
Not "very" tested. (Works on OS X, works on g++ on Linux. That's all I know)
Nicholas Clark
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?).
The RT System itself - Status changed from 'new' to 'open'
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
H.Merijn Brand has reverted the change\, with commit 9945eb56\, so I’m marking this as resolved (at least for now).
@cpansprout - Status changed from 'open' to 'resolved'
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
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
Migrated from rt.perl.org#97672 (status was 'resolved')
Searchable as RT97672$