PR# 18785 REAL_64 constant with value 0.0 produces uncompilable C code on Linux 32-bit
Problem Report Summary
Submitter: prestoat2000
Category: Compiler
Priority: High
Date: 2013/12/23
Class: Bug
Severity: Critical
Number: 18785
Release: 13.11.93542
Confidential: No
Status: Closed
Responsible:
Environment: Linux x86 32-bit
Synopsis: REAL_64 constant with value 0.0 produces uncompilable C code on Linux 32-bit
Description
A class with a declaration angle: REAL_64 = 0.0 causes generation of incorrect C code (and the C code won't compile either). The generated C code for the above declaration is /* {TEST}.angle */ EIF_TYPED_VALUE F859_6932 (EIF_REFERENCE Current) { EIF_TYPED_VALUE r; r.type = SK_REAL64; r.it_r8 = (EIF_REAL_64) -Infinity.; <==== Wrong return r; } -Infinity should be 0. This only happens with the Red Hat Enterprise Linux 32-bit compiler. The 64-bit version generates the correct C code. The Solaris SPARC and Solaris x86 versions also generate correct C code (for both 32-bit and 64-bit versions). Added test ccomp089 for this bug. We cannot upgrade to 13.11 until this is resolved.
To Reproduce
Run eweasel test ccomp089.
Problem Report Interactions
The 64-bit Linux release seems to be fine (possibly just luck with the C compiler optimizer?). Thanks for addressing this.
I put the runtime for the 32-bit version at: ftp://beta:beta57@ftp.eiffel.com/13.11/runtime_suncc_13.11.tgz Let me know if you also need the 64-bit version.
I finally got around to installing the new version (with the run-time fix in place). When I precompile EiffelBase, the C code all compiles but the link fails with: /home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/lib/libwkbench.a(interp.o): In function `interpret': interp.c:(.text+0xd39e): undefined reference to `__divdi3' interp.c:(.text+0xd46c): undefined reference to `__udivdi3' interp.c:(.text+0xd952): undefined reference to `__moddi3' interp.c:(.text+0xdbf4): undefined reference to `__umoddi3' /home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/lib/libwkbench.a(wmisc.o): In function `eif_sleep': misc.c:(.text+0x266): undefined reference to `__divdi3' misc.c:(.text+0x28b): undefined reference to `__moddi3' Looks like the runtime was compiled with gcc instead of cc. Can you give me a new version? I think I just need the contents of $ISE_EIFFEL/studio/spec/linux-x86/lib where runtime is compiled with Sun cc.
I've put a fixed release of 13.11 on your ftp account at Eiffel Software. This is not a new version, I've merely manually patched the runtime and reran the delivery process against the same version of the generated code.
Fixed added in rev#93937.
I do not have an explanation. I'll redo a 13.11 delivery with this fix included and hopefully this will work properly for you too.
With the runtime with the union fix, the test case correctly prints 0. So we are left with one mystery: why did the original runtime produce correct results for you (0) but wrong for me (-Infinity).
It does but so was my previous fix and although it changed what you observed it was still broken. I'll compile a runtime with this union fix included and we will see.
I would like to see a version of libfinalized.a where you have added printf statements after the call to `ieee_init' to print the values of eif_real_64_negative_infinity, etc that are set by ieee_init. Also, perhaps some printf statements in `c_buffero_outr64' (in out.c) to print these same values, plus the value of `d'. Then we see what is different. Unless you have a better idea.
I would be interested to know whether the attached file inline_bug_2.c produces correct results when you compile it with your gcc version. I changed ieee_init to use a union. Both gcc and cc produce correct results with both -m32 and -m64 on Solaris SPARC, Solaris x86 and Red Hat Linux.
Yes, indeed I know that and I should implement this properly. But this still doesn't tell us why it works for me and not for you as this is exactly the same code we are running. This is very peculiar.
I think that the following may explain why your gcc is producing code that doesn't work. The code in ieee_init may be violating strict aliasing rules and unless code is compiled with -fno-strict-aliasing the results may be undefined. See http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html Apologies in advance if you already know about this and it is not relevant. They suggest using a union, which although is not technically allowed seems to work with all major compilers.
I compared the md5sum values with my versions. All were identical except for libmtwkbench.a (because I was using the version with the "volatile" change). I reverted to the one that matches the md5sum value you sent (the original GPL version). Of course, that didn't make any difference because only libfinalized.a is being linked in and its md5sum value matches your value. Here's my results, in case you see something wrong: /bin/rm -f test gcc -o test -O3 -pipe -march=i686 -D_GNU_SOURCE -m32 -DEIF_IEEE_BEHAVIOR -I"/home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/include" -I. -m32 C14/Cobj14.o C13/Cobj13.o C12/Cobj12.o C11/Cobj11.o C10/Cobj10.o C9/Cobj9.o C8/Cobj8.o C7/Cobj7.o C6/Cobj6.o C5/Cobj5.o C4/Cobj4.o C3/Cobj3.o C2/Cobj2.o C1/Cobj1.o E2/Eobj2.o E1/eref.o E1/epoly.o E1/esize.o E1/eplug.o E1/eskelet.o E1/enames.o E1/evisib.o E1/ececil.o E1/einit.o E1/eparents.o E1/emain.o \ "/home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/lib/libfinalized.a" -lm hilbert 151% hilbert 151 .... Output truncated, Click download to get the full message
Unfortunately it prints 0 for me. This is compiled against the runtime and header files of ISE EiffelStudio version 13.11.9.3542 GPL Edition - linux-x86 The runtime are: -rw-r--r-- 1 manus users 429216 Nov 26 01:26 libfinalized.a -rwxr-xr-x 1 manus users 388692 Nov 26 01:26 libfinalized.so* -rw-r--r-- 1 manus users 506334 Nov 26 01:26 libmtfinalized.a -rwxr-xr-x 1 manus users 464083 Nov 26 01:26 libmtfinalized.so* -rw-r--r-- 1 manus users 711008 Nov 26 01:26 libmtwkbench.a -rwxr-xr-x 1 manus users 654779 Nov 26 01:26 libmtwkbench.so* -rw-r--r-- 1 manus users 627194 Nov 26 01:26 libwkbench.a -rwxr-xr-x 1 manus users 574987 Nov 26 01:26 libwkbench.so* ubuntu804 [Manu] : md5sum * 5a0d1717177c8ef04ae1e9ff04b7d860 libfinalized.a cd67f2a6f1d8941309ab0f7a15df676d libfinalized.so 1332f9d2085d1a02f9675e0bfefd2f6e libmtfinalized.a 5e26db2afbecf08b4522696f5f57cd34 libmtfinalized.so fd7206b97c6eff3965d32d9d1c276da0 libmtwkbench.a 220af722eb837704e980637c6b71cd8b libmtwkbench.so e024db84076 .... Output truncated, Click download to get the full message
The attachment is missing.
I'm getting a little confused too. I have attached the F_code directory from the test case. Compiling the code with Sun cc on Solaris x86 produces an executable that works correctly (prints 0). Compiling the code with gcc on Linux x86 (with CFLAGS set to "-pipe -march=i686 -D_GNU_SOURCE -m32") and linking with /home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/lib/libfinalized.a (where libfinalized.a is from GPL version) produces an executable that instead prints -Infinity. Let me know if this wasn't what you were asking for.
Actually I'm now getting very confused with all those different behaviors. The compiler I'm using is the one that was compiled with the shipped run-time since we run the PorterPackage. To make things easier, could we use the development version of EiffelStudio (i.e. 14.05) to debug this and then we can retrofit to 13.11? To begin with, I'd like if this is possible that you write a program under Solaris that prints values correctly, take the uncompiled F_code of that program and compile it under Linux 32-bit and ensure that it does not work properly. I can then take this F_code and the accompanying Eiffel code and test this on my locale machine. Would this be possible?
It didn't fix the problem. I linked the compiler with the runtime with the volatile workaround and then compiled the test case. It compiled fine, but printed -Infinity instead of 0 when executed (it is supposed to print 0 because angle: REAL_64 = 0.0. I had already modified the C code for {REAL_VALUE_I}.generate to print out the values of positive and negative infinity and NaN. With this latest runtime, the output is eif_real_64_negative_infinity is inf eif_real_64_positive is inf eif_real_64_nan is inf Previously, all of these values were 0.000000.
I can disable the optimization by adding a volatile at the right place in ieee_init. I'll adopt this for a solution since it does not cost in performance. However, if I compile the following program: class A create make feature make do io.put_double (d) io.put_new_line io.put_double ({REAL_64}.negative_infinity) io.put_new_line end t: REAL_64 = 0.0 end and then compile it (first it compiles just fine for me), second when executed it prints 0 and -Infinity as expected. I'm going to send you a runtime with the volatile fix in it and see if it solves the issue or not.
Here is our current output: ubuntu804 [Manu] : gcc -O3 test.c -I $ISE_EIFFEL/studio/spec/linux-x86/include/ ubuntu804 [Manu] : ./a.out Negative infinity 32 = 0.000000 Positive infinity 32 = 0.000000 Not a number 32 = 0.000000 Negative infinity 64 = 0.000000 Positive infinity 64 = 0.000000 Not a number 64 = 0.000000
Please try compiling and executing the attached test program on Linux. For me, it produces the correct results: Negative infinity 32 = -inf Positive infinity 32 = inf Not a number 32 = nan Negative infinity 64 = -inf Positive infinity 64 = inf Not a number 64 = nan I'm curious to see whether it produces correct results for you with -O3. I used the following command line: gcc -Wall -O3 -I /home/eiffel/Eiffel13.11.93542/studio/spec/linux-x86/include -o inline_bug -m32 inline_bug.c
I am including this summary of what we have discovered so far, though most of the communication was done directly via e-mail with Manu. After considerable experimentation, it appears that this is a bug in the gcc optimizer. When the run-time is compiled with -O0, a compiler linked with that runtime produces correct C code. When the runtime is compiled with -O3, a compiler linked with that runtime produces wrong C code. Note that this only happens with the gcc version Manu is currently using: gcc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu4) With my version (gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)), it seems to generate correct C code with optimization level -O3. Since the runtime for 7.3 does not have this problem, I wonder whether your compiler was updated to a newer version after 7.3 was released. I also do not understand why you cannot reproduce this problem, since the file libmtwkbench.a seems to have incorrect code for ieee_init (inlined into eif_rtinit). I have attached the log .... Output truncated, Click download to get the full message
Let's touch base Thursday morning and figure out a way to debug this.
So where do we go from here? Perhaps you could tell me how to debug this with a workbench version of estudio. I suppose it could be a bug specific to Red Hat Enterprise Linux 6.5 (but we still have the 6.4 kernel), though that doesn't seem likely either. I will be back to work on Thursday January 2.
The test eweasel test#ccomp089 works just fine for me. All my locale are set to C. I'm note sure what would cause this.
Now I can't seem to get correct C code generated for a class with a constant attribute angle: REAL_64 = 0.0 Not sure why it seemed to work with LANG set to "C" yesterday. I have tried setting LANG to "C", setting LC_ALL to "C", unsetting LANG and all the LC_* environment variables. In all cases, the compiler generates "-Infinity." instead of "0." for the constant attribute above. So unless you can give me some magic incantation, this release is unusable for us (on 32-bit Linux, but we now have some 32-bit Linux programs in production). We do have some REAL_64 constants with value 0.0 in our source code, so this isn't just a theoretical concern. For example, I cannot freeze our big graphical application with 13.11 Linux 32-bit compiler due to this problem. I will be on vacation after today until January 2. I hope we can resolve this after the holidays.
I'm surprised that the underlying parsing tools would produce -Infinity for "0.0" with LANG set to en_US.UTF-8. If it isn't too much trouble, could you point me to the routine or routines you are calling to do the conversion of the "0.0" string to a numeric value (double)? I want to understand this a little better.
This has been a long standing issue with European systems. We just need to not rely on the underlying C parsing tools for floating number in our Eiffel parser. I'll try again to see if we can avoid this.
Your guess is correct: fermi.isi.edu 26% echo $LANG en_US.UTF-8 If I do setenv LANG "C" then it works. With the 64-bit Linux compiler, it works correctly regardless of whether LANG is set to "en_US.UTF-8" or "C".
Could you check your LANG variable? I'm guessing it is not set to C and that some language specific translation turns the 0.0 into the -Infinity number.