Skip to content
Permalink
Browse files
8274944: AppCDS dump causes SEGV in VM thread while adjusting lambda …
…proxy class info

Reviewed-by: minqi, dholmes
  • Loading branch information
calvinccheung committed Oct 26, 2021
1 parent 82f4aac commit e5cd2692da6327c6fde954f86595a08fe5edf43f
Showing 9 changed files with 248 additions and 0 deletions.
@@ -112,6 +112,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
// Block concurrent class unloading from changing the _dumptime_table
MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
SystemDictionaryShared::check_excluded_classes();
SystemDictionaryShared::cleanup_lambda_proxy_class_dictionary();

// save dumptime tables
SystemDictionaryShared::clone_dumptime_tables();
@@ -521,6 +521,7 @@ void VM_PopulateDumpSharedSpace::doit() {
// Block concurrent class unloading from changing the _dumptime_table
MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
SystemDictionaryShared::check_excluded_classes();
SystemDictionaryShared::cleanup_lambda_proxy_class_dictionary();

StaticArchiveBuilder builder;
builder.gather_source_objs();
@@ -1598,6 +1598,28 @@ void SystemDictionaryShared::restore_dumptime_tables() {
_cloned_dumptime_lambda_proxy_class_dictionary = NULL;
}

class CleanupDumpTimeLambdaProxyClassTable: StackObj {
public:
bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
assert_lock_strong(DumpTimeTable_lock);
for (int i = 0; i < info._proxy_klasses->length(); i++) {
InstanceKlass* ik = info._proxy_klasses->at(i);
if (!ik->can_be_verified_at_dumptime()) {
info._proxy_klasses->remove_at(i);
}
}
return info._proxy_klasses->length() == 0 ? true /* delete the node*/ : false;
}
};

void SystemDictionaryShared::cleanup_lambda_proxy_class_dictionary() {
assert_lock_strong(DumpTimeTable_lock);
if (_dumptime_lambda_proxy_class_dictionary != NULL) {
CleanupDumpTimeLambdaProxyClassTable cleanup_proxy_classes;
_dumptime_lambda_proxy_class_dictionary->unlink(&cleanup_proxy_classes);
}
}

#if INCLUDE_CDS_JAVA_HEAP

class ArchivedMirrorPatcher {
@@ -288,6 +288,7 @@ class SystemDictionaryShared: public SystemDictionary {
static size_t estimate_size_for_archive();
static void write_to_archive(bool is_static_archive = true);
static void adjust_lambda_proxy_class_dictionary();
static void cleanup_lambda_proxy_class_dictionary();
static void serialize_dictionary_headers(class SerializeClosure* soc,
bool is_static_archive = true);
static void serialize_vm_classes(class SerializeClosure* soc);
@@ -355,6 +355,7 @@ hotspot_appcds_dynamic = \
-runtime/cds/appcds/DumpClassList.java \
-runtime/cds/appcds/DumpClassListWithLF.java \
-runtime/cds/appcds/ExtraSymbols.java \
-runtime/cds/appcds/LambdaContainsOldInf.java \
-runtime/cds/appcds/LambdaEagerInit.java \
-runtime/cds/appcds/LambdaProxyClasslist.java \
-runtime/cds/appcds/LambdaVerificationFailedDuringDump.java \
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2021, 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
* @bug 8274944
* @summary VM should not crash during CDS dump when a lambda proxy class
* contains an old version of interface.
* @requires vm.cds
* @library /test/lib
* @compile test-classes/OldProvider.jasm
* @compile test-classes/LambdaContainsOldInfApp.java
* @run driver LambdaContainsOldInf
*/

import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.process.OutputAnalyzer;

public class LambdaContainsOldInf {

public static void main(String[] args) throws Exception {
String mainClass = "LambdaContainsOldInfApp";
String namePrefix = "lambdacontainsoldinf";
JarBuilder.build(namePrefix, mainClass, "OldProvider");

String appJar = TestCommon.getTestJar(namePrefix + ".jar");
String classList = namePrefix + ".list";
String archiveName = namePrefix + ".jsa";

// dump class list
CDSTestUtils.dumpClassList(classList, "-cp", appJar, mainClass);

// create archive with the class list
CDSOptions opts = (new CDSOptions())
.addPrefix("-XX:ExtraSharedClassListFile=" + classList,
"-cp", appJar,
"-Xlog:class+load,cds")
.setArchiveName(archiveName);
OutputAnalyzer output = CDSTestUtils.createArchiveAndCheck(opts);
TestCommon.checkExecReturn(output, 0, true,
"Skipping OldProvider: Old class has been linked");
output.shouldMatch("Skipping.LambdaContainsOldInfApp[$][$]Lambda[$].*0x.*:.*Old.class.has.been.linked");

// run with archive
CDSOptions runOpts = (new CDSOptions())
.addPrefix("-cp", appJar, "-Xlog:class+load,cds=debug")
.setArchiveName(archiveName)
.setUseVersion(false)
.addSuffix(mainClass);
output = CDSTestUtils.runWithArchive(runOpts);
TestCommon.checkExecReturn(output, 0, true,
"[class,load] LambdaContainsOldInfApp source: shared objects file");
output.shouldMatch(".class.load. OldProvider.source:.*lambdacontainsoldinf.jar")
.shouldMatch(".class.load. LambdaContainsOldInfApp[$][$]Lambda[$].*/0x.*source:.*LambdaContainsOldInf");
}
}
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2021, 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
* @bug 8274944
* @summary VM should not crash during CDS dump when a lambda proxy class
* contains an old version of interface.
* @requires vm.cds
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
* /test/hotspot/jtreg/runtime/cds/appcds/test-classes
* /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes
* @build LambdaContainsOldInfApp sun.hotspot.WhiteBox OldProvider LambdaVerification
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar lambda_contains_old_inf.jar LambdaVerification
* LambdaContainsOldInfApp OldProvider
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar sun.hotspot.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. LambdaContainsOldInf
*/

import jdk.test.lib.helpers.ClassFileInstaller;

public class LambdaContainsOldInf extends DynamicArchiveTestBase {
public static void main(String[] args) throws Exception {
runTest(LambdaContainsOldInf::test);
}

static void test() throws Exception {
String topArchiveName = getNewArchiveName();
String appJar = ClassFileInstaller.getJarPath("lambda_contains_old_inf.jar");
String mainClass = "LambdaContainsOldInfApp";
String wbJar = ClassFileInstaller.getJarPath("WhiteBox.jar");
String use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;

dump(topArchiveName,
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-Xlog:class+load=debug,cds=debug,cds+dynamic=info",
use_whitebox_jar,
"-cp", appJar, mainClass)
.assertNormalExit(output -> {
output.shouldContain("Skipping OldProvider: Old class has been linked")
.shouldMatch("Skipping.LambdaContainsOldInfApp[$][$]Lambda[$].*0x.*:.*Old.class.has.been.linked")
.shouldHaveExitValue(0);
});

run(topArchiveName,
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
use_whitebox_jar,
"-Xlog:class+load=debug",
"-cp", appJar, mainClass)
.assertNormalExit(output -> {
output.shouldContain("[class,load] LambdaContainsOldInfApp source: shared objects file (top)")
.shouldMatch(".class.load. OldProvider.source:.*lambda_contains_old_inf.jar")
.shouldMatch(".class.load. LambdaContainsOldInfApp[$][$]Lambda[$].*/0x.*source:.*LambdaContainsOldInf")
.shouldHaveExitValue(0);
});
}
}
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2021, 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.
*
*/
public class LambdaContainsOldInfApp {
public static void main(final String... args) {
getProvider();
}

public static OldProvider getProvider() {
return () -> {
return null;
};
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2021, 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.
*
*/
public interface OldProvider
version 49:0
{
public abstract Method get:"()Ljava/lang/Object;";

} // end Class OldProvider

1 comment on commit e5cd269

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on e5cd269 Oct 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.