如何在Java中产生已编译的代码分段错误?

时间:2018-12-05 09:09:45

标签: java jvm

我看到了类似how-do-you-crash-a-jvmshortest-code-that-raises-a-sigsegv这样的问题
有一些Java代码可以生成SIGSEGV,例如:

final Constructor<Unsafe> unsafeConstructor = Unsafe.class.getDeclaredConstructor();
unsafeConstructor.setAccessible(true);
final Unsafe unsafe = unsafeConstructor.newInstance();
System.out.println(unsafe.getAddress(0));

并生成SIGSEGV类型的V(VM帧)。

# JRE version: Java(TM) SE Runtime Environment (8.0_101-b13) (build 1.8.0_101-b13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.101-b13 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# V  [jvm.dll+0x1e2440]

根据https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/crashes001.html,有Crash in Compiled Code

我想知道是否仍然会产生类型为J的分段错误。
而且我看到了一些JVM crash之类的lib问题。(因此表明它可以手动生成吗?)

2 个答案:

答案 0 :(得分:5)

这是一个可在已编译代码中重现崩溃的程序。

import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class Crash extends Thread {
    static volatile Object obj = 0;

    public static void main(String[] args) throws Exception {
        new Crash().start();

        // Give some time to compile run() method
        Thread.sleep(2000);

        Field f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);

        // Overwrite Object's class field, so that 'instanceof' cannot work
        unsafe.putInt(obj, 8L, -1);
    }

    public void run() {
        while (!(obj instanceof Runnable)) {
            // Loop until crash
        }
    }
}

它是如何工作的。 (或者说“ 如何工作”是正确的:)

  1. 运行无限循环的线程。该循环显然是“热”的,因此该方法将进行JIT编译。
  2. instanceof支票无法优化,因为obj易变。
  3. 一段时间后,我们通过在偏移量#8的类字段中写入垃圾来破坏obj头。
  4. 这会破坏编译后的代码,因为instanceof检查依赖于对象类。

这就是我们要得到的。

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000000368b6ad, pid=9660, tid=0x00000000000032f0
#
# JRE version: Java(TM) SE Runtime Environment (8.0_192-b12) (build 1.8.0_192-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.192-b12 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# J 38% C2 Crash.run()V (13 bytes) @ 0x000000000368b6ad [0x000000000368b640+0x6d]
#

答案 1 :(得分:2)

当JVM像这样崩溃时,它会在内联后显示实际的堆栈跟踪。这意味着已内联的方法不会出现。

您可以做的是运行一个测试,将该代码预热到内联Unsafe的位置,然后您可以触发崩溃,该崩溃似乎是由Java方法引起的,但是,真正的原因是内联。