[10] RFR(M): 8176506: C2: loop unswitching and unsafe accesses cause crash

Volker Simonis volker.simonis at gmail.com
Wed May 3 19:29:34 UTC 2017


Hi Roland,

first of all, I think you still have a small error in sparc.ad. I
think the "size(8)" is not right because I see the following error at
VM startup:

#  Internal Error (ad_sparc.cpp:15486), pid=11655, tid=73
#  assert(VerifyOops || MachNode::size(ra_) <= 8) failed: bad fixed size

Current CompileTask:
C2:   2241   16       4       java.lang.StringLatin1::hashCode (42 bytes)

Stack: [0xffffffff45200000,0xffffffff45300000],
sp=0xffffffff452fadd0,  free space=1003k
Native frames: (J=compiled Java code, A=aot compiled Java code,
j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x1c7ce4c]  void VMError::report_and_die(int,const
char*,const char*,void*,Thread*,unsigned char*,void*,void*,const
char*,int,unsigned long)+0x894
V  [libjvm.so+0x1c7c4fc]  void VMError::report_and_die(Thread*,const
char*,int,const char*,const char*,void*)+0x6c
V  [libjvm.so+0xfed1dc]  void report_vm_error(const char*,int,const
char*,const char*,...)+0xc4
V  [libjvm.so+0x96b118]  unsigned
ShouldNotReachHereNode::size(PhaseRegAlloc*)const+0xd8
V  [libjvm.so+0x1923ac0]  void
Compile::shorten_branches(unsigned*,int&,int&,int&)+0x6c0
V  [libjvm.so+0x19279d4]  CodeBuffer*Compile::init_buffer(unsigned*)+0x3e4
V  [libjvm.so+0x1922d08]  void Compile::Output()+0x730
V  [libjvm.so+0xf247d0]  void Compile::Code_Gen()+0x610
V  [libjvm.so+0xf1a624]
Compile::Compile(ciEnv*,C2Compiler*,ciMethod*,int,bool,bool,bool,DirectiveSet*)+0x1894
...

Removing the "size()" instruction altogether, fixes the problem (but
there's probably a better solution).

I've also looked at your change and I think it works fine on
ppc64/s390x because we've always implemented the HaltNode by issuing a
trap instructions. So with your change (and your modified test) we
will just crash in the generates C2 method which I think is fine:

#  SIGTRAP (0x5) at pc=0x00003fff47b12bd8, pid=19883, tid=19964

J 215 c2 TestMaybeNullUnsafeAccess.test2(Ljava/lang/Object;)I (34
bytes) @ 0x00003fff47b12bd8 [0x00003fff47b12b80+0x0000000000000058]
j  TestMaybeNullUnsafeAccess.main([Ljava/lang/String;)V+49
v  ~StubRoutines::call_stub

I'm not sure if your change to the implementation of the HaltNode
(i.e. calling ShouldNotReachHere()) is really the best solution. With
that change, a crash due to an Unsafe NULL access looks as follows on
SPARC:

#  Internal Error
(/usr/work/d046063/OpenJDK/jdk10-hs/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp:1378),
pid=29415, tid=87
#  Error: ShouldNotReachHere()

V  [libjvm.so+0x1c7cd0c]  void VMError::report_and_die(int,const
char*,const char*,void*,Thread*,unsigned char*,void*,void*,const
char*,int,unsigned long)+0x894
V  [libjvm.so+0x1c7c3bc]  void VMError::report_and_die(Thread*,const
char*,int,const char*,const char*,void*)+0x6c
V  [libjvm.so+0xfed034]  void report_vm_error(const char*,int,const
char*,const char*,...)+0xc4
V  [libjvm.so+0xfecf4c]  void report_vm_error(const char*,int,const char*)+0x64
V  [libjvm.so+0xfed3a0]  void report_should_not_reach_here(const char*,int)+0x48
V  [libjvm.so+0x1754c64]  void halt()+0x34
J 216 c2 TestMaybeNullUnsafeAccess.test2(Ljava/lang/Object;)I (34
bytes) @ 0xffffffff53412884 [0xffffffff53412820+0x0000000000000064]
j  TestMaybeNullUnsafeAccess.main([Ljava/lang/String;)V+49

I think this may be quite confusing to users/support because you can
not easily see that it is related to an illegal Unsafe access. It
looks more like an error in macroAssembler_sparc.cpp:1378 (and
ShouldNotReachHere() is usually used for errors in the VM and not to
signal user errors).

I obviously prefer the first crash, so maybe you can at least only
change the platforms which called "breakpoint()" until now?

Not sure if this is easily possible, but I think an ideal solution
would be to really execute the actual, offending load instead of
inserting a HaltNode. That would give you a nice hs_err file on all
platforms where the registers would even contain the offending address
(NULL) and the offset. I think this could simplify troubleshooting in
the case of a crash. What do you think?

Please find some other minor comments/suggestions below:

src/share/vm/opto/graphKit.cpp

+// add a check for null for which one branch can't be taken. It uses
+// and Opaque4 node that will cause the check to be removed after loop

- should probably read "// an Opaque4 node.." in the second line

src/share/vm/opto/opaquenode.hpp

+// know implicitly is always true of false but the compiler has no way
+// to prove. If during optimizations, that check becomes true of

- s/of/or/

test/compiler/unsafe/TestMaybeNullUnsafeAccess.java

- wouldn't it be safer to run the test with -Xbatch and
-XX:-UseOnStackReplacement for any case and to make it evident that
the test relays on the fact that test1() and test2() should be
compiled but not inlined ?

- you should also update the copyright on most files you've touched.

Regards,
Volker

On Wed, May 3, 2017 at 9:58 AM, Roland Westrelin <rwestrel at redhat.com> wrote:
>
>> Looks good to me. I will submit RBT testing, lets see how it goes.
>
> Thanks, Vladimir.
>
> Note that usual testing shouldn't cause the Halt to be executed so
> wouldn't test its new implementation.
>
> Roland.


More information about the hotspot-compiler-dev mailing list