Undefined behaviour in hotspot
Mikael Gerdin
mikael.gerdin at oracle.com
Tue Apr 22 08:31:37 UTC 2014
Hi Omair,
On Monday 21 April 2014 11.19.56 Omair Majid wrote:
> Hi,
>
> I recently tried to build OpenJDK on i686 using a prerelease version of GCC
> 4.9. It turns out that new optimizations have been enabled in GCC which now
> cause hotspot to break in a few places where hotspot relies on undefined
> behaviour.
>
> $ uname -a
> Linux rawhide 3.15.0-0.rc1.git1.1.fc21.i686+PAE #1 SMP Tue Apr 15 14:40:42
> UTC 2014 i686 i686 i386 GNU/Linux
>
> $ gcc --version
> gcc (GCC) 4.9.0 20140411 (Red Hat 4.9.0-0.10)
> Copyright (C) 2014 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions. There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>
> A `java -version` is sufficient to trigger a crash:
>
> $ ./build/images/j2sdk-image/bin/java -version
> #
> # A fatal error has been detected by the Java Runtime Environment:
> #
> # SIGSEGV (0xb) at pc=0xb637a10e, pid=1014, tid=3053837120
> #
> # JRE version: (8.0_05-b13) (build )
> # Java VM: OpenJDK Server VM (25.5-b02-fastdebug mixed mode linux-x86 )
> # Problematic frame:
> # V [libjvm.so+0x31c10e] Assembler::push(RegisterImpl*)+0x4e
> #
> # Failed to write core dump. Core dumps have been disabled. To enable
> # core dumping, try "ulimit -c unlimited" before starting Java again
> #
> # An error report file with more information is saved as:
> # /home/omajid/java-1.8.0-openjdk/hs_err_pid1014.log
> #
> # If you would like to submit a bug report, please visit:
> # http://bugreport.sun.com/bugreport/crash.jsp
> #
>
> The above report is from jdk8u5b13 (also, [1]), but this is reproducible on
> jdk8-b132 [2] and jdk7u [3] as well.
>
> Following the advice posted here [4], I built OpenJDK8 with
> "-fsanitize=undefined" which pointed out:
>
> /home/omajid/java-1.8.0-openjdk/java-1.8.0-openjdk/jdk8/hotspot/src/share/vm
> /code/relocInfo.hpp:855:24: runtime error: load of null pointer of type
> '<unknown> *'
> /home/omajid/java-1.8.0-openjdk/java-1.8.0-openjdk/jdk8/hotspot/src/share/v
> m/asm/codeBuffer.hpp:181:51: runtime error: member access within null
> pointer of type 'struct CodeSection' ==15676==ERROR: SanitizerTool failed
> to allocate 0x200000 (2097152) bytes of SizeClassAllocator32: 12
> ==15676==Process memory map follows:
> 0x00100000-0x00200000
>
> (snip)
>
> 0xbff8f000-0xbffb0000 [stack]
> ==15676==End of process memory map.
> ==15676==Sanitizer CHECK failed:
> ../../../../libsanitizer/sanitizer_common/sanitizer_posix.cc:66 (("unable
> to mmap" && 0)) != (0) (0, 0)
>
> I ran through the code with gdb. Please ignore the java-abrt executable
> name: on Fedora, jre/bin/java-abrt is the original jre/bin/java and
> jre/bin/java is a shell script that runs jre/bin/java-abrt with additional
> options.
>
> (gdb) r -version
> Starting program:
> /home/omajid/java-1.8.0-openjdk/java-1.8.0-openjdk/jdk8/build/jdk8.build/im
> ages/j2sdk-image/jre/bin/java-abrt -version [Thread debugging using
> libthread_db enabled]
> Using host libthread_db library "/lib/libthread_db.so.1".
> [New Thread 0xb689bb40 (LWP 15144)]
>
> Program received signal SIGSEGV, Segmentation fault.
> [Switching to Thread 0xb689bb40 (LWP 15144)]
> 0xb6bb810e in Assembler::push (this=0xb689ae14, src=0x0)
> at
> /home/omajid/java-1.8.0-openjdk/java-1.8.0-openjdk/jdk8/hotspot/src/cpu/x86
> /vm/assembler_x86.cpp:2580 2580 emit_int8(0x50 | encode);
> (gdb) l
> 2575 }
> 2576
> 2577 void Assembler::push(Register src) {
> 2578 int encode = prefix_and_encode(src->encoding());
> 2579
> 2580 emit_int8(0x50 | encode);
> 2581 }
> 2582
> 2583 void Assembler::pushf() {
> 2584 emit_int8((unsigned char)0x9C);
> (gdb) p encode
> $1 = <optimized out>
> (gdb) p src
> $2 = (Register) 0x0
>
> Dereferencing a NULL pointer is undefined behaviour in C++ [5] and it seems
> perfectly acceptable for a compiler to compile hotspot in a way so that it
> ends up not working.
A related (questionable) practice of calling member functions on null pointers
is pretty common in hotspot, for example:
inline bool oopDesc::is_oop_or_null(bool ignore_mark_word) const {
return this == NULL ? true : is_oop(ignore_mark_word);
}
I think it would be a good idea to try to address as many as possible of the
undefined behaviors we rely on since I believe it will significantly reduce
the problems we will face in future porting and compiler version upgrade
projects.
/Mikael
>
> If I disable optimizations done by the compiler (using slowdebug), then the
> built copy of hotspot works correctly. Both fastdebug and release (which
> keep compiler optimizations enabled) result in builds that crash when run.
>
> Obviously, I would like to get hotspot to work correctly when compiled
> against GCC 4.9. But I believe the micro-optimizations made to use the
> address of the object instead of using a field in the object is to save
> space and I would rather not blindly undo it. Does anyone here have any
> advice on what the best course of action there is?
>
> Thanks,
> Omair
>
> [1] http://kojipkgs.fedoraproject.org//work/tasks/4320/6744320/build.log
> [2] http://kojipkgs.fedoraproject.org//work/tasks/6501/6746501/build.log
> [3] http://kojipkgs.fedoraproject.org//work/tasks/5509/6755509/build.log
> [4] https://lists.fedoraproject.org/pipermail/devel/2014-April/197741.html
> [5] http://stackoverflow.com/questions/2474018/
More information about the hotspot-dev
mailing list