1 /*
2  * Copyright (c) 2016, 2020, 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  * @test
26  * @bug 8140520
27  * @summary Setting small CompilerThreadStackSize, ThreadStackSize, and
28  * VMThreadStackSize values should result in an error message that shows
29  * the minimum stack size value for each thread type.
30  * @library /test/lib
31  * @modules java.base/jdk.internal.misc
32  *          java.management
33  * @run driver TooSmallStackSize
34  */
35 
36 /*
37  * The primary purpose of this test is to make sure we can run with a
38  * stack smaller than the minimum without crashing. Also this test will
39  * determine the minimum allowed stack size for the platform (as
40  * provided by the JVM error message when a very small stack is used),
41  * and then verify that the JVM can be launched with that stack size
42  * without a crash or any error messages.
43  *
44  * Note: The '-Xss<size>' and '-XX:ThreadStackSize=<k-bytes>' options
45  * both control Java thread stack size. This repo's version of the test
46  * exercises the '-XX:ThreadStackSize' VM option. The jdk repo's version
47  * of the test exercises the '-Xss' option.
48  */
49 
50 import jdk.test.lib.process.ProcessTools;
51 import jdk.test.lib.process.OutputAnalyzer;
52 
53 public class TooSmallStackSize {
54     /* for debugging. Normally false. */
55     static final boolean verbose = false;
56     static final String CompilerThreadStackSizeString = "CompilerThreadStackSize";
57     static final String ThreadStackSizeString = "Java thread stack size";
58     static final String VMThreadStackSizeString = "VMThreadStackSize";
59 
60     /*
61      * Returns the minimum stack size this platform will allowed based on the
62      * contents of the error message the JVM outputs when too small of a
63      * stack size was used.
64      *
65      * The testOutput argument must contain the result of having already run
66      * the JVM with too small of a stack size.
67      */
getMinStackAllowed(String testOutput)68     static String getMinStackAllowed(String testOutput) {
69         /*
70          * The JVM output will contain in one of the lines:
71          *   "The CompilerThreadStackSize specified is too small. Specify at least 100k"
72          *   "The Java thread stack size specified is too small. Specify at least 100k"
73          *   "The VMThreadStackSize specified is too small. Specify at least 100k"
74          * Although the actual size will vary. We need to extract this size
75          * string from the output and return it.
76          */
77         String matchStr = "Specify at least ";
78         int match_idx = testOutput.indexOf(matchStr);
79         if (match_idx >= 0) {
80             int size_start_idx = match_idx + matchStr.length();
81             int k_start_idx = testOutput.indexOf("k", size_start_idx);
82             // don't include the 'k'; the caller will have to
83             // add it back as needed.
84             return testOutput.substring(size_start_idx, k_start_idx);
85         }
86 
87         System.out.println("Expect='" + matchStr + "'");
88         System.out.println("Actual: " + testOutput);
89         System.out.println("FAILED: Could not get the stack size from the output");
90         throw new RuntimeException("test fails");
91     }
92 
93     /*
94      * Run the JVM with the specified stack size.
95      *
96      * Returns the minimum allowed stack size gleaned from the error message,
97      * if there is an error message. Otherwise returns the stack size passed in.
98      */
checkStack(String stackOption, String optionMesg, String stackSize)99     static String checkStack(String stackOption, String optionMesg, String stackSize) throws Exception {
100         String min_stack_allowed;
101 
102         System.out.println("*** Testing " + stackOption + stackSize);
103 
104         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
105             stackOption + stackSize,
106             // Uncomment the following to get log output
107             // that shows actual thread creation sizes.
108             // "-Xlog:os+thread",
109             "-version");
110 
111         OutputAnalyzer output = new OutputAnalyzer(pb.start());
112 
113         if (verbose) {
114             System.out.println("stdout: " + output.getStdout());
115         }
116 
117         if (output.getExitValue() == 0) {
118             // checkMinStackAllowed() is called with stackSize values
119             // that should be the minimum that works. This method,
120             // checkStack(), is called with stackSize values that
121             // should be too small and result in error messages.
122             // However, some platforms fix up a stackSize value that is
123             // too small into something that works so we have to allow
124             // for checkStack() calls that work.
125             System.out.println("PASSED: got exit_code == 0 with " + stackOption + stackSize);
126             min_stack_allowed = stackSize;
127         } else {
128             String expect = "The " + optionMesg + " specified is too small";
129             if (verbose) {
130                 System.out.println("Expect='" + expect + "'");
131             }
132             output.shouldContain(expect);
133             min_stack_allowed = getMinStackAllowed(output.getStdout());
134 
135             System.out.println("PASSED: got expected error message with " + stackOption + stackSize);
136         }
137 
138         return min_stack_allowed;
139     }
140 
141     /*
142      * Run the JVM with the minimum allowed stack size. This should always succeed.
143      */
checkMinStackAllowed(String stackOption, String optionMesg, String stackSize)144     static void checkMinStackAllowed(String stackOption, String optionMesg, String stackSize) throws Exception {
145         System.out.println("*** Testing " + stackOption + stackSize);
146 
147         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
148             stackOption + stackSize,
149             // Uncomment the following to get log output
150             // that shows actual thread creation sizes.
151             // "-Xlog:os+thread",
152             "-version");
153 
154         OutputAnalyzer output = new OutputAnalyzer(pb.start());
155         output.shouldHaveExitValue(0);
156 
157         System.out.println("PASSED: VM launched with " + stackOption + stackSize);
158     }
159 
main(String... args)160     public static void main(String... args) throws Exception {
161         /*
162          * The result of a 16k stack size should be a quick exit with a complaint
163          * that the stack size is too small. However, for some win32 builds, the
164          * stack is always at least 64k, and this also sometimes is the minimum
165          * allowed size, so we won't see an error in this case.
166          *
167          * This test case will also produce a crash on some platforms if the fix
168          * for 6762191 is not yet in place.
169          */
170         checkStack("-XX:ThreadStackSize=", ThreadStackSizeString, "16");
171 
172         /*
173          * Try with a 64k stack size, which is the size that the launcher will
174          * set to if you try setting to anything smaller. This should produce the same
175          * result as setting to 16k if the fix for 6762191 is in place.
176          */
177         String min_stack_allowed = checkStack("-XX:ThreadStackSize=", ThreadStackSizeString, "64");
178 
179         /*
180          * Try again with a the minimum stack size that was given in the error message
181          */
182         checkMinStackAllowed("-XX:ThreadStackSize=", ThreadStackSizeString, min_stack_allowed);
183 
184         /*
185          * Now try with a stack size that is not page aligned.
186          */
187         checkMinStackAllowed("-XX:ThreadStackSize=", ThreadStackSizeString, "513");
188 
189         /*
190          * Try with 0k which indicates that the default thread stack size from JVM will be used.
191          */
192         checkMinStackAllowed("-XX:ThreadStackSize=", ThreadStackSizeString, "0");
193 
194         /*
195          * Now redo the same tests with the compiler thread stack size:
196          */
197         checkStack("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "16");
198         min_stack_allowed = checkStack("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "64");
199         checkMinStackAllowed("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, min_stack_allowed);
200         checkMinStackAllowed("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "513");
201         checkMinStackAllowed("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "0");
202 
203         /*
204          * Now redo the same tests with the VM thread stack size:
205          */
206         checkStack("-XX:VMThreadStackSize=", VMThreadStackSizeString, "16");
207         min_stack_allowed = checkStack("-XX:VMThreadStackSize=", VMThreadStackSizeString, "64");
208         checkMinStackAllowed("-XX:VMThreadStackSize=", VMThreadStackSizeString, min_stack_allowed);
209         checkMinStackAllowed("-XX:VMThreadStackSize=", VMThreadStackSizeString, "513");
210         checkMinStackAllowed("-XX:VMThreadStackSize=", VMThreadStackSizeString, "0");
211     }
212 }
213