1
+ /*
2
+ * Copyright (c) 2023, 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.
8
+ *
9
+ * This code is distributed in the hope that it will be useful, but WITHOUT
10
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
+ * version 2 for more details (a copy is included in the LICENSE file that
13
+ * accompanied this code).
14
+ *
15
+ * You should have received a copy of the GNU General Public License version
16
+ * 2 along with this work; if not, write to the Free Software Foundation,
17
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
+ *
19
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
+ * or visit www.oracle.com if you need additional information or have any
21
+ * questions.
22
+ *
23
+ */
24
+
25
+ import jdk .test .lib .process .OutputAnalyzer ;
26
+ import jdk .test .lib .process .ProcessTools ;
27
+ import jdk .test .lib .Utils ;
28
+ import java .util .ArrayList ;
29
+ import java .util .Arrays ;
30
+ import java .util .List ;
31
+
32
+ /*
33
+ * @test StackWalkNativeToJava
34
+ * @bug 8316309
35
+ * @summary Check that walking the stack works fine when going from C++ frame to Java frame.
36
+ * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64"
37
+ * @requires os.family != "windows"
38
+ * @requires vm.flagless
39
+ * @library /test/lib
40
+ * @run driver StackWalkNativeToJava
41
+ */
42
+
43
+ public class StackWalkNativeToJava {
44
+
45
+ public static void main (String [] args ) throws Exception {
46
+ // Check stack walking works fine when sender of C++ frame
47
+ // is a Java native method.
48
+ testStackWalkNativeToJavaNative ("-Xint" );
49
+ testStackWalkNativeToJavaNative ("-Xcomp" , "-XX:CompileCommand=dontinline,StackWalkNativeToJava$TestNativeToJavaNative::*" );
50
+
51
+ // Check stack walking works fine when sender of C++ frame
52
+ // is a runtime stub or interpreted Java method (VM call from Java).
53
+ testStackWalkNativeToJava ("-Xint" );
54
+ testStackWalkNativeToJava ("-Xcomp" , "-XX:TieredStopAtLevel=3" ,
55
+ "-XX:CompileCommand=dontinline,StackWalkNativeToJava$TestNativeToJava::*" );
56
+ }
57
+
58
+ public static void testStackWalkNativeToJavaNative (String ... extraFlags ) throws Exception {
59
+ List <String > commands = new ArrayList <>();
60
+ commands .add ("-Xbootclasspath/a:." );
61
+ commands .add ("-XX:-CreateCoredumpOnCrash" );
62
+ commands .add ("-XX:+UnlockDiagnosticVMOptions" );
63
+ commands .add ("-XX:AbortVMOnException=java.lang.IllegalMonitorStateException" );
64
+ commands .add ("-XX:+ErrorFileToStdout" );
65
+ commands .addAll (Arrays .asList (extraFlags ));
66
+ commands .add ("StackWalkNativeToJava$TestNativeToJavaNative" );
67
+
68
+ ProcessBuilder pb = ProcessTools .createJavaProcessBuilder (commands );
69
+ OutputAnalyzer output = new OutputAnalyzer (pb .start ());
70
+ output .shouldNotContain ("java.lang.RuntimeException: Reached statement after obj.wait()" );
71
+ output .shouldNotContain ("[error occurred during error reporting (printing native stack" );
72
+ String [] res = output .getOutput ().split ("StackWalkNativeToJava\\ $TestNativeToJavaNative\\ .callNativeMethod\\ (\\ )V" );
73
+ assertTrue (res .length - 1 == 2 , res .length - 1 );
74
+ output .shouldNotHaveExitValue (0 );
75
+ }
76
+
77
+ public static class TestNativeToJavaNative {
78
+ public static void main (String [] args ) throws Exception {
79
+ TestNativeToJavaNative test = new TestNativeToJavaNative ();
80
+ test .callNativeMethod ();
81
+ }
82
+
83
+ public void callNativeMethod () throws Exception {
84
+ Object obj = new Object ();
85
+ // Trigger a fatal exit due to IllegalMonitorStateException during
86
+ // a call to the VM from a Java native method.
87
+ obj .wait ();
88
+ throw new RuntimeException ("Reached statement after obj.wait()" );
89
+ }
90
+ }
91
+
92
+ public static void testStackWalkNativeToJava (String ... extraFlags ) throws Exception {
93
+ List <String > commands = new ArrayList <>();
94
+ commands .add ("-Xbootclasspath/a:." );
95
+ commands .add ("-XX:-CreateCoredumpOnCrash" );
96
+ commands .add ("-XX:+UnlockDiagnosticVMOptions" );
97
+ commands .add ("-XX:DiagnoseSyncOnValueBasedClasses=1" );
98
+ commands .add ("-XX:+ErrorFileToStdout" );
99
+ commands .addAll (Arrays .asList (extraFlags ));
100
+ commands .add ("StackWalkNativeToJava$TestNativeToJava" );
101
+
102
+ ProcessBuilder pb = ProcessTools .createJavaProcessBuilder (commands );
103
+ OutputAnalyzer output = new OutputAnalyzer (pb .start ());
104
+ output .shouldNotContain ("java.lang.RuntimeException: Reached statement after synchronized" );
105
+ output .shouldNotContain ("[error occurred during error reporting (printing native stack" );
106
+ String [] res = output .getOutput ().split ("StackWalkNativeToJava\\ $TestNativeToJava\\ .callVMMethod\\ (\\ )V" );
107
+ assertTrue (res .length - 1 == 2 , res .length - 1 );
108
+ output .shouldNotHaveExitValue (0 );
109
+ }
110
+
111
+ public static class TestNativeToJava {
112
+ static Integer counter = 0 ;
113
+
114
+ public static void main (String [] args ) throws Exception {
115
+ TestNativeToJava test = new TestNativeToJava ();
116
+ test .callVMMethod ();
117
+ }
118
+
119
+ public void callVMMethod () throws Exception {
120
+ // Trigger a fatal exit for trying to synchronize on a value based class
121
+ // during a call to the VM from a Java method.
122
+ synchronized (counter ) {
123
+ counter ++;
124
+ }
125
+ throw new RuntimeException ("Reached statement after synchronized" );
126
+ }
127
+ }
128
+
129
+ private static void assertTrue (boolean condition , int count ) {
130
+ if (!condition ) {
131
+ throw new RuntimeException ("Count error: count was " + count );
132
+ }
133
+ }
134
+ }
0 commit comments