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