1 /*
   2  * Copyright (c) 2016, 2017, 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: 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      */
  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      */
  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      */
 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 
 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          * Now redo the same tests with the compiler thread stack size:
 191          */
 192         checkStack("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "16");
 193         min_stack_allowed = checkStack("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "64");
 194         checkMinStackAllowed("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, min_stack_allowed);
 195         checkMinStackAllowed("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "513");
 196 
 197         /*
 198          * Now redo the same tests with the VM thread stack size:
 199          */
 200         checkStack("-XX:VMThreadStackSize=", VMThreadStackSizeString, "16");
 201         min_stack_allowed = checkStack("-XX:VMThreadStackSize=", VMThreadStackSizeString, "64");
 202         checkMinStackAllowed("-XX:VMThreadStackSize=", VMThreadStackSizeString, min_stack_allowed);
 203         checkMinStackAllowed("-XX:VMThreadStackSize=", VMThreadStackSizeString, "513");
 204     }
 205 }