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