8222334: java -Xss0 triggers StackOverflowError
authorqpzhang
Tue, 16 Apr 2019 11:00:48 +0000
changeset 54543 4fc566b7a9c0
parent 54542 0a4214c90a55
child 54544 97a4b8f46a49
8222334: java -Xss0 triggers StackOverflowError Summary: Launcher to use the stack size decided by hotpot or system if -Xss is 0 Reviewed-by: dholmes, alanb
src/java.base/share/native/libjli/java.c
test/hotspot/jtreg/runtime/Thread/TooSmallStackSize.java
test/jdk/tools/launcher/TooSmallStackSize.java
--- a/src/java.base/share/native/libjli/java.c	Tue Apr 16 08:51:01 2019 +0200
+++ b/src/java.base/share/native/libjli/java.c	Tue Apr 16 11:00:48 2019 +0000
@@ -204,11 +204,14 @@
  */
 static jlong threadStackSize    = 0;  /* stack size of the new thread */
 static jlong maxHeapSize        = 0;  /* max heap size */
-static jlong initialHeapSize    = 0;  /* inital heap size */
+static jlong initialHeapSize    = 0;  /* initial heap size */
 
 /*
- * A minimum -Xss stack size suitable for all platforms.
- */
+ * A minimum initial-thread stack size suitable for most platforms.
+ * This is the minimum amount of stack needed to load the JVM such
+ * that it can reject a too small -Xss value. If this is too small
+ * JVM initialization would cause a StackOverflowError.
+  */
 #ifndef STACK_SIZE_MINIMUM
 #define STACK_SIZE_MINIMUM (64 * KB)
 #endif
@@ -934,16 +937,18 @@
     options[numOptions].optionString = str;
     options[numOptions++].extraInfo = info;
 
+    /*
+     * -Xss is used both by the JVM and here to establish the stack size of the thread
+     * created to launch the JVM. In the latter case we need to ensure we don't go
+     * below the minimum stack size allowed. If -Xss is zero that tells the JVM to use
+     * 'default' sizes (either from JVM or system configuration, e.g. 'ulimit -s' on linux),
+     * and is not itself a small stack size that will be rejected. So we ignore -Xss0 here.
+     */
     if (JLI_StrCCmp(str, "-Xss") == 0) {
         jlong tmp;
         if (parse_size(str + 4, &tmp)) {
             threadStackSize = tmp;
-            /*
-             * Make sure the thread stack size is big enough that we won't get a stack
-             * overflow before the JVM startup code can check to make sure the stack
-             * is big enough.
-             */
-            if (threadStackSize < (jlong)STACK_SIZE_MINIMUM) {
+            if (threadStackSize > 0 && threadStackSize < (jlong)STACK_SIZE_MINIMUM) {
                 threadStackSize = STACK_SIZE_MINIMUM;
             }
         }
@@ -2322,38 +2327,38 @@
                     int argc, char **argv,
                     int mode, char *what, int ret)
 {
-
-    /*
-     * If user doesn't specify stack size, check if VM has a preference.
-     * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will
-     * return its default stack size through the init args structure.
-     */
     if (threadStackSize == 0) {
-      struct JDK1_1InitArgs args1_1;
-      memset((void*)&args1_1, 0, sizeof(args1_1));
-      args1_1.version = JNI_VERSION_1_1;
-      ifn->GetDefaultJavaVMInitArgs(&args1_1);  /* ignore return value */
-      if (args1_1.javaStackSize > 0) {
-         threadStackSize = args1_1.javaStackSize;
-      }
+        /*
+         * If the user hasn't specified a non-zero stack size ask the JVM for its default.
+         * A returned 0 means 'use the system default' for a platform, e.g., Windows.
+         * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will
+         * return its default stack size through the init args structure.
+         */
+        struct JDK1_1InitArgs args1_1;
+        memset((void*)&args1_1, 0, sizeof(args1_1));
+        args1_1.version = JNI_VERSION_1_1;
+        ifn->GetDefaultJavaVMInitArgs(&args1_1);  /* ignore return value */
+        if (args1_1.javaStackSize > 0) {
+            threadStackSize = args1_1.javaStackSize;
+        }
     }
 
     { /* Create a new thread to create JVM and invoke main method */
-      JavaMainArgs args;
-      int rslt;
+        JavaMainArgs args;
+        int rslt;
 
-      args.argc = argc;
-      args.argv = argv;
-      args.mode = mode;
-      args.what = what;
-      args.ifn = *ifn;
+        args.argc = argc;
+        args.argv = argv;
+        args.mode = mode;
+        args.what = what;
+        args.ifn = *ifn;
 
-      rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args);
-      /* If the caller has deemed there is an error we
-       * simply return that, otherwise we return the value of
-       * the callee
-       */
-      return (ret != 0) ? ret : rslt;
+        rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args);
+        /* If the caller has deemed there is an error we
+         * simply return that, otherwise we return the value of
+         * the callee
+         */
+        return (ret != 0) ? ret : rslt;
     }
 }
 
--- a/test/hotspot/jtreg/runtime/Thread/TooSmallStackSize.java	Tue Apr 16 08:51:01 2019 +0200
+++ b/test/hotspot/jtreg/runtime/Thread/TooSmallStackSize.java	Tue Apr 16 11:00:48 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -187,12 +187,18 @@
         checkMinStackAllowed("-XX:ThreadStackSize=", ThreadStackSizeString, "513");
 
         /*
+         * Try with 0k which indicates that the default thread stack size from JVM will be used.
+         */
+        checkMinStackAllowed("-XX:ThreadStackSize=", ThreadStackSizeString, "0");
+
+        /*
          * Now redo the same tests with the compiler thread stack size:
          */
         checkStack("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "16");
         min_stack_allowed = checkStack("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "64");
         checkMinStackAllowed("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, min_stack_allowed);
         checkMinStackAllowed("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "513");
+        checkMinStackAllowed("-XX:CompilerThreadStackSize=", CompilerThreadStackSizeString, "0");
 
         /*
          * Now redo the same tests with the VM thread stack size:
@@ -201,5 +207,6 @@
         min_stack_allowed = checkStack("-XX:VMThreadStackSize=", VMThreadStackSizeString, "64");
         checkMinStackAllowed("-XX:VMThreadStackSize=", VMThreadStackSizeString, min_stack_allowed);
         checkMinStackAllowed("-XX:VMThreadStackSize=", VMThreadStackSizeString, "513");
+        checkMinStackAllowed("-XX:VMThreadStackSize=", VMThreadStackSizeString, "0");
     }
 }
--- a/test/jdk/tools/launcher/TooSmallStackSize.java	Tue Apr 16 08:51:01 2019 +0200
+++ b/test/jdk/tools/launcher/TooSmallStackSize.java	Tue Apr 16 11:00:48 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6762191
+ * @bug 6762191 8222334
  * @summary Setting stack size to 16K causes segmentation fault
  * @compile TooSmallStackSize.java
  * @run main TooSmallStackSize
@@ -171,5 +171,11 @@
          * asserts added for 8176768 are not triggered.
          */
         checkMinStackAllowed("513k");
+
+        /*
+         * Try with 0k which indicates that the default thread stack size either from JVM or system
+         * will be used, this should always succeed.
+         */
+        checkMinStackAllowed("0k");
     }
 }