mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
214 lines
9.6 KiB
Java
214 lines
9.6 KiB
Java
/*
|
|
* Copyright (c) 2025, Red Hat, Inc.
|
|
* Copyright (c) 2025, 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
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/*
|
|
* @test id=no_coh_no_cds
|
|
* @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone
|
|
* @library /test/lib
|
|
* @requires vm.bits == 64 & vm.debug == true & vm.flagless
|
|
* @requires os.family != "aix"
|
|
* @modules java.base/jdk.internal.misc
|
|
* java.management
|
|
* @build jdk.test.whitebox.WhiteBox
|
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
|
* @run driver AccessZeroNKlassHitsProtectionZone no_coh_no_cds
|
|
*/
|
|
|
|
/*
|
|
* @test id=no_coh_cds
|
|
* @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone
|
|
* @requires vm.cds & vm.bits == 64 & vm.debug == true & vm.flagless
|
|
* @requires os.family != "aix"
|
|
* @library /test/lib
|
|
* @modules java.base/jdk.internal.misc
|
|
* java.management
|
|
* @build jdk.test.whitebox.WhiteBox
|
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
|
* @run driver AccessZeroNKlassHitsProtectionZone no_coh_cds
|
|
*/
|
|
|
|
/*
|
|
* @test id=coh_no_cds
|
|
* @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone
|
|
* @requires vm.bits == 64 & vm.debug == true & vm.flagless
|
|
* @requires os.family != "aix"
|
|
* @library /test/lib
|
|
* @modules java.base/jdk.internal.misc
|
|
* java.management
|
|
* @build jdk.test.whitebox.WhiteBox
|
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
|
* @run driver AccessZeroNKlassHitsProtectionZone coh_no_cds
|
|
*/
|
|
|
|
/*
|
|
* @test id=coh_cds
|
|
* @summary Test that dereferencing a Klass that is the result of a decode(0) crashes accessing the nKlass guard zone
|
|
* @requires vm.cds & vm.bits == 64 & vm.debug == true & vm.flagless
|
|
* @requires os.family != "aix"
|
|
* @library /test/lib
|
|
* @modules java.base/jdk.internal.misc
|
|
* java.management
|
|
* @build jdk.test.whitebox.WhiteBox
|
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
|
* @run driver AccessZeroNKlassHitsProtectionZone coh_cds
|
|
*/
|
|
|
|
import jdk.test.lib.process.OutputAnalyzer;
|
|
import jdk.test.lib.process.ProcessTools;
|
|
import jdk.test.whitebox.WhiteBox;
|
|
import jtreg.SkippedException;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.regex.Pattern;
|
|
|
|
// Test that dereferencing a Klass that is the result of a narrowKlass=0 will give us immediate crashes
|
|
// that hit the protection zone at encoding base.
|
|
public class AccessZeroNKlassHitsProtectionZone {
|
|
|
|
private static OutputAnalyzer run_test(boolean COH, boolean CDS, String forceBaseString) throws IOException, SkippedException {
|
|
ArrayList<String> args = new ArrayList<>();
|
|
args.add("-Xbootclasspath/a:.");
|
|
args.add("-XX:+UnlockDiagnosticVMOptions");
|
|
args.add("-XX:+WhiteBoxAPI");
|
|
args.add("-XX:CompressedClassSpaceSize=128m");
|
|
args.add("-Xmx128m");
|
|
args.add("-XX:-CreateCoredumpOnCrash");
|
|
args.add("-Xlog:metaspace*");
|
|
args.add("-Xlog:cds");
|
|
if (COH) {
|
|
args.add("-XX:+UseCompactObjectHeaders");
|
|
}
|
|
if (CDS) {
|
|
args.add("-Xshare:on");
|
|
} else {
|
|
args.add("-Xshare:off");
|
|
args.add("-XX:CompressedClassSpaceBaseAddress=" + forceBaseString);
|
|
}
|
|
args.add(AccessZeroNKlassHitsProtectionZone.class.getName());
|
|
args.add("runwb");
|
|
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args.toArray(new String[0]));
|
|
|
|
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
|
output.reportDiagnosticSummary();
|
|
return output;
|
|
}
|
|
|
|
private static void run_test(boolean COH, boolean CDS) throws IOException, SkippedException {
|
|
// Notes:
|
|
// We want to enforce zero-based encoding, to test the protection page in that case. For zero-based encoding,
|
|
// protection page is at address zero, no need to test that.
|
|
// If CDS is on, we never use zero-based, forceBase is ignored.
|
|
// If CDS is off, we use forceBase to (somewhat) reliably force the encoding base to beyond 32G,
|
|
// in order to prevent zero-based encoding. Since that may fail, we try several times.
|
|
OutputAnalyzer output = null;
|
|
long forceBase = -1;
|
|
if (CDS) {
|
|
output = run_test(COH, CDS, "");
|
|
// Not all distributions build COH archives. We tolerate that.
|
|
if (COH) {
|
|
String s = output.firstMatch("Specified shared archive file not found .*coh.jsa");
|
|
if (s != null) {
|
|
throw new SkippedException("Failed to find COH archive, was it not built? Skipping test.");
|
|
}
|
|
}
|
|
} else {
|
|
long g4 = 0x1_0000_0000L;
|
|
long start = g4 * 8; // 32g
|
|
long step = g4;
|
|
long end = start + step * 16;
|
|
for (forceBase = start; forceBase < end; forceBase += step) {
|
|
String thisBaseString = String.format("0x%016X", forceBase).toLowerCase();
|
|
output = run_test(COH, CDS, thisBaseString);
|
|
if (output.contains("CompressedClassSpaceBaseAddress=" + thisBaseString + " given, but reserving class space failed.")) {
|
|
// try next one
|
|
} else if (output.contains("Successfully forced class space address to " + thisBaseString)) {
|
|
break;
|
|
} else {
|
|
throw new RuntimeException("Unexpected");
|
|
}
|
|
}
|
|
if (forceBase >= end) {
|
|
throw new SkippedException("Failed to force ccs to any of the given bases. Skipping test.");
|
|
}
|
|
}
|
|
|
|
// Parse the encoding base from the output. In case of CDS, it depends on ASLR. Even in case of CDS=off, we want
|
|
// to double-check it is the force address.
|
|
String nKlassBaseString = output.firstMatch("Narrow klass base: 0x([0-9a-f]+)", 1);
|
|
if (nKlassBaseString == null) {
|
|
throw new RuntimeException("did not find Narrow klass base in log output");
|
|
}
|
|
long nKlassBase = Long.valueOf(nKlassBaseString, 16);
|
|
|
|
if (!CDS && nKlassBase != forceBase) {
|
|
throw new RuntimeException("Weird - we should have mapped at force base"); // .. otherwise we would have skipped out above
|
|
}
|
|
if (nKlassBase == 0) {
|
|
throw new RuntimeException("We should not be running zero-based at this point.");
|
|
}
|
|
|
|
// Calculate the expected crash address pattern. The precise crash address is unknown, but should be located
|
|
// in the lower part of the guard page following the encoding base. We just accept any address matching the
|
|
// upper 52 digits (leaving 4K = 12 bits = 4 nibbles of wiggle room)
|
|
String expectedCrashAddressString = nKlassBaseString.substring(0, nKlassBaseString.length() - 3);
|
|
|
|
// output from whitebox function: Klass* should point to encoding base
|
|
output.shouldMatch("WB_DecodeNKlassAndAccessKlass: nk 0 k 0x" + nKlassBaseString);
|
|
|
|
// Then, we should have crashed
|
|
output.shouldNotHaveExitValue(0);
|
|
output.shouldContain("# A fatal error has been detected");
|
|
|
|
// The hs-err file should contain a reference to the nKlass protection zone, like this:
|
|
// "RDI=0x0000000800000000 points into nKlass protection zone"
|
|
File hsErrFile = HsErrFileUtils.openHsErrFileFromOutput(output);
|
|
|
|
ArrayList<Pattern> hsErrPatternList = new ArrayList<>();
|
|
hsErrPatternList.add(Pattern.compile(".*(SIGBUS|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).*"));
|
|
|
|
hsErrPatternList.add(Pattern.compile(".*siginfo:.*" + expectedCrashAddressString + ".*"));
|
|
hsErrPatternList.add(Pattern.compile(".*" + expectedCrashAddressString + ".*points into nKlass protection zone.*"));
|
|
Pattern[] hsErrPattern = hsErrPatternList.toArray(new Pattern[0]);
|
|
HsErrFileUtils.checkHsErrFileContent(hsErrFile, hsErrPattern, true);
|
|
}
|
|
|
|
enum Argument { runwb, no_coh_no_cds, no_coh_cds, coh_no_cds, coh_cds };
|
|
public static void main(String[] args) throws Exception {
|
|
if (args.length != 1) {
|
|
throw new RuntimeException("Expecting one argument");
|
|
}
|
|
Argument arg = Argument.valueOf(args[0]);
|
|
System.out.println(arg);
|
|
switch (arg) {
|
|
case runwb -> WhiteBox.getWhiteBox().decodeNKlassAndAccessKlass(0);
|
|
case no_coh_no_cds -> run_test(false, false);
|
|
case no_coh_cds -> run_test(false, true);
|
|
case coh_no_cds -> run_test(true, false);
|
|
case coh_cds -> run_test(true, true);
|
|
}
|
|
}
|
|
}
|