Note: This is a public test instance of Red Hat Bugzilla. The data contained within is a snapshot of the live data so any changes you make will not be reflected in the production Bugzilla. Email is disabled so feel free to test any aspect of the site that you want. File any problems you find or give feedback at bugzilla.redhat.com.

Bug 1215127

Summary: Miscompilation of hotspot's type.o due to value range propagation on trees (tree-vrp) optimization
Product: [Fedora] Fedora Reporter: Severin Gehwolf <sgehwolf>
Component: gccAssignee: Jakub Jelinek <jakub>
Status: CLOSED NOTABUG QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 22CC: davejohansen, jakub, jwakely, law, mpolacek, omajid
Target Milestone: ---   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2015-04-24 15:12:30 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
reproducer.sh
none
type.o.i (with some __attribute__ tries which I've added)
none
0001-spec-file-patch-for-GCC-reproducer.patch
none
relink.sh none

Description Severin Gehwolf 2015-04-24 11:10:00 UTC
Created attachment 1018412 [details]
reproducer.sh

Description of problem:
GCC 5 miscompiles one object of libjvm.so (from the java-1.8.0-openjdk package) incorrectly. I've narrowed it down to type.o but I was yet unsuccessful to narrow it down further. For more background see bug 1208369.

Version-Release number of selected component (if applicable):
gcc-5.0.0-0.21.fc22.x86_64

How reproducible:
100%

Steps to Reproduce:
1. Build a java-1.8.0-openjdk fast debug build using the attached spec file patch. I can provide srpm if needed.
1.1 $ fedpkg clone java-1.8.0-openjdk
1.2 $ fedpkg switch-branch f22
1.3 $ git checkout db2c528191c5b19dca09d6e234e6bdcedaebc1bb
1.4 $ git am 0001-spec-file-patch-for-GCC-reproducer.patch
1.5.$ fedpkg local
2. In directory java-1.8.0-openjdk/$NVR.$ARCH/jdk8/build/jdk8.build/hotspot/linux_amd64_compiler2/fastdebug all the *.o objects needed.
3. copy type.o.i into that dir
4. cd into java-1.8.0-openjdk/$NVR.$ARCH/jdk8/build/jdk8.build/hotspot/linux_amd64_compiler2/fastdebug
5. $ rm -f type.o && rm -f libjvm.so && /usr/bin/g++ -fPIC -fno-rtti -fno-exceptions -fcheck-new -fvisibility=hidden -m64  -pipe -fno-strict-aliasing  -g -O3 -Werror -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wunused-value -fstack-protector-strong -fno-devirtualize -Wno-return-local-addr -c -MMD -MP -MF ../generated/dependencies/type.o.d -fpch-deps -o type.o type.o.i && bash path/to/relink.sh
6. run reproducer.sh script which either asserts as in 
   https://bugzilla.redhat.com/show_bug.cgi?id=1208369#c17 or runs fine
7. BUILD_DIR in reproducer.sh should be java-1.8.0-openjdk/$NVR.$ARCH/jdk8/build/jdk8.build/

Actual results:
Miscompiled object with tree-vrp turned on.

Expected results:
Working type.o with tree-vrp turned on.

Additional info:
Compile attached pre-processed file type.o.i with and without tree-vrp turned on. The resulting type.o will assert in a fastdebug build of java-1.8.0-openjdk and run fine if turned off respectively.

I'll be happy to help if you have trouble reproducing the issue.

Comment 1 Severin Gehwolf 2015-04-24 11:12:05 UTC
Created attachment 1018413 [details]
type.o.i (with some __attribute__ tries which I've added)

Comment 2 Severin Gehwolf 2015-04-24 11:14:06 UTC
Created attachment 1018414 [details]
0001-spec-file-patch-for-GCC-reproducer.patch

Comment 3 Severin Gehwolf 2015-04-24 11:14:41 UTC
Created attachment 1018415 [details]
relink.sh

Comment 4 Jakub Jelinek 2015-04-24 13:18:24 UTC
With all the optimize attributes you have in there this seems to have started with http://gcc.gnu.org/r219823 , but wonder if that isn't exactly because of the optimize attributes with that revision.

Comment 5 Jakub Jelinek 2015-04-24 15:12:04 UTC
So, after removing all the __attribute__((optimize ("O0"))) stuff, I've bisected this to http://gcc.gnu.org/r215697 , which is indeed a VRP change and looking e.g. at vrp1 diffs, I see changes e.g. in TypeInt::xdual or TypeInt::make (i.e. functions that inline normalize_int_widen or normalize_long_widen).

And, by adding noinline/noclone on both normalize_{int,long}_widen, and then optimize (0) on them selectively to find which one is the problem, I've came up with short reproducer:

__attribute__((noinline, noclone)) int
normalize_long_widen (long long lo, long long hi, int w)
{
  if (lo <= hi)
    {
      if ((unsigned long long) (hi - lo) <= 3ULL)
	w = 0;
      if ((unsigned long long) (hi - lo) >= -1ULL)
	w = 3;
    }
  else
    {
      if ((unsigned long long) (lo - hi) <= 3ULL)
	w = 0;
      if ((unsigned long long) (lo - hi) >= -1ULL)
	w = 0;
    }
  return w;
}

int
main ()
{
  __builtin_printf ("%d\n", normalize_long_widen (-__LONG_LONG_MAX__ - 1,
                                                  __LONG_LONG_MAX__, 16));
  return 0;
}

and that just seems that hotspot relies on undefined behavior, as LONG_LONG_MIN is smaller than LONG_LONG_MAX (thus lo <= hi is true), but hi - lo is undefined behavior.

Guess you want something like (so that the subtraction is performed in unsigned type with well defined overflow):
--- type.o.i~	2015-04-24 14:17:08.000000000 +0200
+++ type.o.i	2015-04-24 17:07:08.258819716 +0200
@@ -129471,11 +129471,11 @@ static int normalize_int_widen( jint lo,
 
 
   if (lo <= hi) {
-    if ((juint)(hi - lo) <= ((juint)3)) w = Type::WidenMin;
-    if ((juint)(hi - lo) >= max_juint) w = Type::WidenMax;
+    if ((juint)hi - lo <= ((juint)3)) w = Type::WidenMin;
+    if ((juint)hi - lo >= max_juint) w = Type::WidenMax;
   } else {
-    if ((juint)(lo - hi) <= ((juint)3)) w = Type::WidenMin;
-    if ((juint)(lo - hi) >= max_juint) w = Type::WidenMin;
+    if ((juint)lo - hi <= ((juint)3)) w = Type::WidenMin;
+    if ((juint)lo - hi >= max_juint) w = Type::WidenMin;
   }
   return w;
 }
@@ -129753,11 +129753,11 @@ static int normalize_long_widen( jlong l
 
 
   if (lo <= hi) {
-    if ((julong)(hi - lo) <= ((juint)3)) w = Type::WidenMin;
-    if ((julong)(hi - lo) >= max_julong) w = Type::WidenMax;
+    if ((julong)hi - lo <= ((juint)3)) w = Type::WidenMin;
+    if ((julong)hi - lo >= max_julong) w = Type::WidenMax;
   } else {
-    if ((julong)(lo - hi) <= ((juint)3)) w = Type::WidenMin;
-    if ((julong)(lo - hi) >= max_julong) w = Type::WidenMin;
+    if ((julong)lo - hi <= ((juint)3)) w = Type::WidenMin;
+    if ((julong)lo - hi >= max_julong) w = Type::WidenMin;
   }
   return w;
 }

(of course applied to the source, not preprocessed source) as a fix.
Or ((juint)hi - (juint)lo) instead of (juint)hi - lo, depends on the projects coding conventions...
You could have tried -fsanitize=undefined first before filing bugs... (next time).

Comment 6 Severin Gehwolf 2015-04-24 15:26:41 UTC
(In reply to Jakub Jelinek from comment #5)
> You could have tried -fsanitize=undefined first before filing bugs... (next
> time).

Thank you very much for the analysis, Jakub. I'll certainly use -fsanitize=undefined next time before filing bugs. Thanks again!