1 /*
2  * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package jdk.jfr.jvm;
26 
27 import java.io.IOException;
28 import java.nio.file.Files;
29 import java.nio.file.Path;
30 import java.nio.file.Paths;
31 import java.util.List;
32 
33 import jdk.internal.misc.Unsafe;
34 import jdk.jfr.consumer.RecordedEvent;
35 import jdk.jfr.consumer.RecordingFile;
36 import jdk.test.lib.Asserts;
37 import jdk.test.lib.process.OutputAnalyzer;
38 import jdk.test.lib.process.ProcessTools;
39 
40 /**
41  * @test
42  * @key jfr
43  * @summary Verifies that data associated with a running recording can be evacuated to an hs_err_pidXXX.jfr when the VM crashes
44  * @requires vm.hasJFR
45  *
46  * @library /test/lib
47  * @modules java.base/jdk.internal.misc
48  *          java.management
49  *          jdk.jfr
50  *
51  * @run main/othervm --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED jdk.jfr.jvm.TestDumpOnCrash
52  */
53 public class TestDumpOnCrash {
54 
55     private static final CharSequence LOG_FILE_EXTENSION = ".log";
56     private static final CharSequence JFR_FILE_EXTENSION = ".jfr";
57 
58     static class CrasherIllegalAccess {
main(String[] args)59         public static void main(String[] args) {
60             Unsafe.getUnsafe().putInt(0L, 0);
61         }
62     }
63 
64     static class CrasherHalt {
main(String[] args)65         public static void main(String[] args) {
66             System.out.println("Running Runtime.getRuntime.halt");
67             Runtime.getRuntime().halt(17);
68         }
69     }
70 
71     static class CrasherSig {
main(String[] args)72         public static void main(String[] args) throws Exception {
73             String signalName = args[0];
74             System.out.println("Sending SIG" + signalName + " to process " + ProcessHandle.current().pid());
75             Runtime.getRuntime().exec("kill -" + signalName + " " + ProcessHandle.current().pid()).waitFor();
76         }
77     }
78 
main(String[] args)79     public static void main(String[] args) throws Exception {
80         verify(runProcess(CrasherIllegalAccess.class.getName(), "", true));
81         verify(runProcess(CrasherIllegalAccess.class.getName(), "", false));
82         verify(runProcess(CrasherHalt.class.getName(), "", true));
83         verify(runProcess(CrasherHalt.class.getName(), "", false));
84 
85         // Verification is excluded for the test case below until 8219680 is fixed
86         long pid = runProcess(CrasherSig.class.getName(), "FPE", true);
87         // @ignore 8219680
88         // verify(pid);
89     }
90 
runProcess(String crasher, String signal, boolean disk)91     private static long runProcess(String crasher, String signal, boolean disk) throws Exception {
92         System.out.println("Test case for crasher " + crasher);
93         final String flightRecordingOptions = "dumponexit=true,disk=" + Boolean.toString(disk);
94         Process p = ProcessTools.createJavaProcessBuilder(true,
95                 "-Xmx64m",
96                 "-XX:-TransmitErrorReport",
97                 "-XX:-CreateCoredumpOnCrash",
98                 "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
99                 "-XX:StartFlightRecording=" + flightRecordingOptions,
100                 crasher,
101                 signal)
102             .start();
103 
104         OutputAnalyzer output = new OutputAnalyzer(p);
105         System.out.println("========== Crasher process output:");
106         System.out.println(output.getOutput());
107         System.out.println("==================================");
108 
109         return p.pid();
110     }
111 
verify(long pid)112     private static void verify(long pid) throws IOException {
113         String fileName = "hs_err_pid" + pid + ".jfr";
114         Path file = Paths.get(fileName).toAbsolutePath().normalize();
115 
116         Asserts.assertTrue(Files.exists(file), "No emergency jfr recording file " + file + " exists");
117         Asserts.assertNotEquals(Files.size(file), 0L, "File length 0. Should at least be some bytes");
118         System.out.printf("File size=%d%n", Files.size(file));
119 
120         List<RecordedEvent> events = RecordingFile.readAllEvents(file);
121         Asserts.assertFalse(events.isEmpty(), "No event found");
122         System.out.printf("Found event %s%n", events.get(0).getEventType().getName());
123     }
124 }
125