1 /*
   2  * Copyright (c) 2014, 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 /* @test LimitSharedSizes
  25  * @summary Test handling of limits on shared space size
  26  * @library /test/lib /runtime/CommandLine/OptionsValidation/common
  27  * @modules java.base/jdk.internal.misc
  28  *          java.management
  29  *          jdk.attach/sun.tools.attach
  30  * @run main LimitSharedSizes
  31  */
  32 
  33 import jdk.test.lib.process.ProcessTools;
  34 import jdk.test.lib.process.OutputAnalyzer;
  35 import jdk.test.lib.Platform;
  36 import optionsvalidation.JVMOptionsUtils;
  37 
  38 public class LimitSharedSizes {
  39     static enum Result {
  40         OUT_OF_RANGE,
  41         TOO_SMALL,
  42         VALID,
  43         VALID_ARCHIVE
  44     }
  45 
  46     static enum Region {
  47         RO, RW, MD, MC
  48     }
  49 
  50     private static final boolean fitsRange(String name, String value) throws RuntimeException {
  51         boolean fits = true;
  52         try {
  53             fits = JVMOptionsUtils.fitsRange(name, value);
  54         } catch (Exception e) {
  55             throw new RuntimeException(e.getMessage());
  56         }
  57         return fits;
  58     }
  59 
  60     private static class SharedSizeTestData {
  61         public String optionName;
  62         public String optionValue;
  63         public Result optionResult;
  64 
  65         public SharedSizeTestData(Region region, String value) {
  66             optionName = "-XX:"+getName(region);
  67             optionValue = value;
  68             if (fitsRange(getName(region), value) == false) {
  69                 optionResult = Result.OUT_OF_RANGE;
  70             } else {
  71                 optionResult = Result.TOO_SMALL;
  72             }
  73         }
  74 
  75         public SharedSizeTestData(Region region, String value, Result result) {
  76             optionName = "-XX:"+getName(region);
  77             optionValue = value;
  78             optionResult = result;
  79         }
  80 
  81         private String getName(Region region) {
  82             String name;
  83             switch (region) {
  84                 case RO:
  85                     name = "SharedReadOnlySize";
  86                     break;
  87                 case RW:
  88                     name = "SharedReadWriteSize";
  89                     break;
  90                 case MD:
  91                     name = "SharedMiscDataSize";
  92                     break;
  93                 case MC:
  94                     name = "SharedMiscCodeSize";
  95                     break;
  96                 default:
  97                     name = "Unknown";
  98                     break;
  99             }
 100             return name;
 101         }
 102 
 103         public Result getResult() {
 104             return optionResult;
 105         }
 106     }
 107 
 108     private static final SharedSizeTestData[] testTable = {
 109         // Too small of a region size should not cause a vm crash.
 110         // It should result in an error message either like the following #1:
 111         // The shared miscellaneous code space is not large enough
 112         // to preload requested classes. Use -XX:SharedMiscCodeSize=
 113         // to increase the initial size of shared miscellaneous code space.
 114         // or #2:
 115         // The shared miscellaneous code space is outside the allowed range
 116         new SharedSizeTestData(Region.RO, "4M"),
 117         new SharedSizeTestData(Region.RW, "4M"),
 118         new SharedSizeTestData(Region.MD, "50k"),
 119         new SharedSizeTestData(Region.MC, "20k"),
 120 
 121         // these values are larger than default ones, and should
 122         // be acceptable and not cause failure
 123         new SharedSizeTestData(Region.RO, "20M", Result.VALID),
 124         new SharedSizeTestData(Region.RW, "20M", Result.VALID),
 125         new SharedSizeTestData(Region.MD, "20M", Result.VALID),
 126         new SharedSizeTestData(Region.MC, "20M", Result.VALID),
 127 
 128         // test with sizes which just meet the minimum required sizes
 129         // the following tests also attempt to use the shared archive
 130         new SharedSizeTestData(Region.RO, Platform.is64bit() ? "14M":"9M", Result.VALID_ARCHIVE),
 131         new SharedSizeTestData(Region.RW, Platform.is64bit() ? "12M":"7M", Result.VALID_ARCHIVE),
 132         new SharedSizeTestData(Region.MD, Platform.is64bit() ? "4M":"2M", Result.VALID_ARCHIVE),
 133         new SharedSizeTestData(Region.MC, "120k", Result.VALID_ARCHIVE),
 134     };
 135 
 136     public static void main(String[] args) throws Exception {
 137         int counter = 0;
 138         for (SharedSizeTestData td : testTable) {
 139             String fileName = "LimitSharedSizes" + counter + ".jsa";
 140             counter++;
 141 
 142             String option = td.optionName + "=" + td.optionValue;
 143             System.out.println("testing option number <" + counter + ">");
 144             System.out.println("testing option <" + option + ">");
 145 
 146             ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
 147                "-XX:+UnlockDiagnosticVMOptions",
 148                "-XX:SharedArchiveFile=./" + fileName,
 149                option,
 150                "-Xshare:dump");
 151 
 152             OutputAnalyzer output = new OutputAnalyzer(pb.start());
 153 
 154             switch (td.getResult()) {
 155                 case VALID:
 156                 case VALID_ARCHIVE:
 157                 {
 158                   output.shouldNotContain("space is not large enough");
 159                   output.shouldHaveExitValue(0);
 160 
 161                   if (td.getResult() == Result.VALID_ARCHIVE) {
 162                       // try to use the archive
 163                       pb = ProcessTools.createJavaProcessBuilder(
 164                          "-XX:+UnlockDiagnosticVMOptions",
 165                          "-XX:SharedArchiveFile=./" + fileName,
 166                          "-XX:+PrintSharedArchiveAndExit",
 167                          "-version");
 168 
 169                       try {
 170                           output = new OutputAnalyzer(pb.start());
 171                           output.shouldContain("archive is valid");
 172                       } catch (RuntimeException e) {
 173                           // if sharing failed due to ASLR or similar reasons,
 174                           // check whether sharing was attempted at all (UseSharedSpaces)
 175                           if ((output.getOutput().contains("Unable to use shared archive") ||
 176                                output.getOutput().contains("Unable to map ReadOnly shared space at required address.") ||
 177                                output.getOutput().contains("Unable to map ReadWrite shared space at required address.") ||
 178                                output.getOutput().contains("Unable to reserve shared space at required address")) &&
 179                                output.getExitValue() == 1) {
 180                                System.out.println("Unable to use shared archive: test not executed; assumed passed");
 181                                continue;
 182                           }
 183                       }
 184                       output.shouldHaveExitValue(0);
 185                   }
 186                 }
 187                 break;
 188                 case TOO_SMALL:
 189                 {
 190                     output.shouldContain("space is not large enough");
 191                     output.shouldHaveExitValue(2);
 192                 }
 193                 break;
 194                 case OUT_OF_RANGE:
 195                 {
 196                     output.shouldContain("outside the allowed range");
 197                     output.shouldHaveExitValue(1);
 198                 }
 199                 break;
 200             }
 201         }
 202     }
 203 }