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