Skip to content

Commit cae8bbc

Browse files
committedNov 28, 2023
Added CDSConfig::preserve_all_dumptime_verification_states() to control whether classes verified by the old verifier can be archived

File tree

10 files changed

+62
-15
lines changed

10 files changed

+62
-15
lines changed
 

‎src/hotspot/share/cds/cdsConfig.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "cds/heapShared.hpp"
3030
#include "cds/metaspaceShared.hpp"
3131
#include "classfile/classLoaderDataShared.hpp"
32+
#include "classfile/systemDictionaryShared.hpp"
3233
#include "logging/log.hpp"
3334
#include "prims/jvmtiExport.hpp"
3435

@@ -75,6 +76,16 @@ bool CDSConfig::is_dumping_regenerated_lambdaform_invokers() {
7576
}
7677
}
7778

79+
// Preserve all states that were examined used during dumptime verification, such
80+
// that the verification result (pass or fail) cannot be changed at runtime.
81+
//
82+
// For example, if the verification of ik requires that class A must be a subtype of B,
83+
// then this relationship between A and B cannot be changed at runtime. I.e., the app
84+
// cannot load alternative versions of A and B such that A is not a subtype of B.
85+
bool CDSConfig::preserve_all_dumptime_verification_states(const InstanceKlass* ik) {
86+
return PreloadSharedClasses && SystemDictionaryShared::is_builtin(ik);
87+
}
88+
7889
#if INCLUDE_CDS_JAVA_HEAP
7990
bool CDSConfig::is_dumping_heap() {
8091
return is_dumping_static_archive() && !is_dumping_preimage_static_archive()

‎src/hotspot/share/cds/cdsConfig.hpp

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "memory/allStatic.hpp"
2929
#include "utilities/macros.hpp"
3030

31+
class InstanceKlass;
32+
3133
class CDSConfig : public AllStatic {
3234
#if INCLUDE_CDS
3335
static bool _is_dumping_dynamic_archive;
@@ -49,6 +51,9 @@ class CDSConfig : public AllStatic {
4951
static void set_has_preloaded_classes() { CDS_ONLY(_has_preloaded_classes = true); }
5052
static bool is_dumping_regenerated_lambdaform_invokers() NOT_CDS_RETURN_(false);
5153

54+
// Misc CDS features
55+
static bool preserve_all_dumptime_verification_states(const InstanceKlass* ik);
56+
5257
// CDS archived heap
5358
static bool is_dumping_heap() NOT_CDS_JAVA_HEAP_RETURN_(false);
5459
static bool is_loading_heap() NOT_CDS_JAVA_HEAP_RETURN_(false);

‎src/hotspot/share/cds/dumpTimeClassInfo.cpp

+16-3
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,22 @@ bool DumpTimeClassInfo::is_excluded() {
4747
if (_excluded) {
4848
return true;
4949
}
50-
if ((!PreloadSharedClasses || !ArchiveReflectionData || !SystemDictionaryShared::is_builtin(_klass))
51-
&& _failed_verification) {
52-
return true;
50+
if (_failed_verification) {
51+
if (CDSConfig::preserve_all_dumptime_verification_states(_klass)) {
52+
assert(PreloadSharedClasses, "sanity");
53+
// If the verification states are preserved, _klass will be archived in unlinked state. This is
54+
// necessary to support the following scenario, where the verification of X requires that
55+
// A be a subclass of B:
56+
// class X {
57+
// B getB() { return new A(); }
58+
// }
59+
// If X and B can be verified, but A fails verification, we still archive A (in a preloaded
60+
// SystemDictionary) so that at runtime we cannot subvert the verification of X by replacing
61+
// A with a version that is not a subtype of B.
62+
} else {
63+
// Don't archive this class. At runtime, load it from classfile and rerun verification.
64+
return true;
65+
}
5366
}
5467
return false;
5568
}

‎src/hotspot/share/cds/metaspaceShared.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -627,12 +627,16 @@ class CollectCLDClosure : public CLDClosure {
627627
// Check if we can eagerly link this class at dump time, so we can avoid the
628628
// runtime linking overhead (especially verification)
629629
bool MetaspaceShared::may_be_eagerly_linked(InstanceKlass* ik) {
630+
if (CDSConfig::preserve_all_dumptime_verification_states(ik)) {
631+
assert(ik->can_be_verified_at_dumptime(), "sanity");
632+
}
630633
if (!ik->can_be_verified_at_dumptime()) {
631634
// For old classes, try to leave them in the unlinked state, so
632635
// we can still store them in the archive. They must be
633636
// linked/verified at runtime.
634637
return false;
635638
}
639+
636640
if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared_unregistered_class()) {
637641
// Linking of unregistered classes at this stage may cause more
638642
// classes to be resolved, resulting in calls to ClassLoader.loadClass()
@@ -875,7 +879,6 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS
875879

876880
#if INCLUDE_CDS_JAVA_HEAP
877881
if (CDSConfig::is_dumping_heap()) {
878-
StringTable::allocate_shared_strings_array(CHECK);
879882
if (!HeapShared::is_archived_boot_layer_available(THREAD)) {
880883
log_info(cds)("archivedBootLayer not available, disabling full module graph");
881884
CDSConfig::disable_dumping_full_module_graph();
@@ -885,6 +888,10 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS
885888
if (CDSConfig::is_dumping_full_module_graph()) {
886889
HeapShared::reset_archived_object_states(CHECK);
887890
}
891+
892+
// Do this at the very end, when no Java code will be executed. Otherwise
893+
// some new strings may be added to the intern table.
894+
StringTable::allocate_shared_strings_array(CHECK);
888895
}
889896
#endif
890897

‎src/hotspot/share/classfile/stringTable.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,9 @@ oop StringTable::lookup_shared(const jchar* name, int len) {
806806
// This should be called when we know no more strings will be added (which will be easy
807807
// to guarantee because CDS runs with a single Java thread. See JDK-8253495.)
808808
void StringTable::allocate_shared_strings_array(TRAPS) {
809-
assert(CDSConfig::is_dumping_heap(), "must be");
809+
if (!CDSConfig::is_dumping_heap()) {
810+
return;
811+
}
810812
if (_items_count > (size_t)max_jint) {
811813
fatal("Too many strings to be archived: %zu", _items_count);
812814
}

‎src/hotspot/share/classfile/systemDictionaryShared.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
315315
}
316316
}
317317

318-
if (!PreloadSharedClasses || !ArchiveReflectionData || !is_builtin(k)) {
318+
if (!CDSConfig::preserve_all_dumptime_verification_states(k)) {
319319
if (!k->is_linked()) {
320320
if (has_class_failed_verification(k)) {
321321
return warn_excluded(k, "Failed verification");
@@ -337,7 +337,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
337337
if (ArchiveInvokeDynamic && HeapShared::is_archivable_hidden_klass(k)) {
338338
// Allow Lambda Proxy and LambdaForm classes, for ArchiveInvokeDynamic only
339339
} else {
340-
log_debug(cds)("Skipping %s: Hidden class", k->name()->as_C_string());
340+
log_info(cds)("Skipping %s: Hidden class", k->name()->as_C_string());
341341
return true;
342342
}
343343
}

‎src/hotspot/share/oops/instanceKlass.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -2966,13 +2966,8 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
29662966
}
29672967
}
29682968

2969-
// Check if a class or any of its supertypes has a version older than 50.
2970-
// CDS will not perform verification of old classes during dump time because
2971-
// without changing the old verifier, the verification constraint cannot be
2972-
// retrieved during dump time.
2973-
// Verification of archived old classes will be performed during run time.
29742969
bool InstanceKlass::can_be_verified_at_dumptime() const {
2975-
if (PreloadSharedClasses && SystemDictionaryShared::is_builtin(this)) {
2970+
if (CDSConfig::preserve_all_dumptime_verification_states(this)) {
29762971
return true;
29772972
}
29782973

@@ -2987,6 +2982,11 @@ bool InstanceKlass::can_be_verified_at_dumptime() const {
29872982
return true;
29882983
}
29892984

2985+
// Check if a class or any of its supertypes has a version older than 50.
2986+
// CDS will not perform verification of old classes during dump time because
2987+
// without changing the old verifier, the verification constraint cannot be
2988+
// retrieved during dump time.
2989+
// Verification of archived old classes will be performed during run time.
29902990
if (major_version() < 50 /*JAVA_6_VERSION*/) {
29912991
return false;
29922992
}

‎src/hotspot/share/runtime/arguments.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -3185,7 +3185,13 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
31853185
}
31863186

31873187
if (!CDSConfig::is_dumping_static_archive() || !PreloadSharedClasses) {
3188+
// FIXME -- CDSConfig::is_dumping_heap() is not yet callable from here, as UseG1GC is not yet set by ergo!
3189+
//
3190+
//
3191+
// These optimizations require heap dumping and PreloadSharedClasses, or else
3192+
// the classes of some archived heap objects may be replaced at runtime.
31883193
ArchiveInvokeDynamic = false;
3194+
ArchiveReflectionData = false;
31893195
}
31903196
#endif
31913197

‎test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/OldClassVerifierTrouble.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ private static void doTestCustomBase(String topArchiveName) throws Exception {
6565
// create a custom base archive containing an old class
6666
OutputAnalyzer output = TestCommon.dump(appJar,
6767
TestCommon.list("VerifierTroubleApp", "VerifierTroublev49", "ChildOldSuper"),
68-
"-Xlog:class+load,cds+class=debug");
68+
"-Xlog:class+load,cds+class=debug",
69+
"-XX:-PreloadSharedClasses");
6970
TestCommon.checkDump(output);
7071
// Check the ChildOldSuper and VerifierTroublev49 are being dumped into the base archive.
7172
output.shouldMatch(".cds.class.*klass.*0x.*app.*ChildOldSuper.*unlinked")
@@ -79,6 +80,7 @@ private static void doTestCustomBase(String topArchiveName) throws Exception {
7980
// Linking VerifierTroublev49 would result in java.lang.VerifyError.
8081
dump2(baseArchiveName, topArchiveName,
8182
"-Xlog:cds,cds+dynamic,class+load,cds+class=debug",
83+
"-XX:-PreloadSharedClasses",
8284
"-cp", appJar,
8385
appClass)
8486
.assertAbnormalExit(out -> {

‎test/hotspot/jtreg/runtime/cds/appcds/preloadedClasses/PreloadedClassVerification.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ public static void main(String[] args) throws Exception {
6969
"BadNewClass",
7070
"BadNewClass2",
7171
"GoodOldClass"),
72-
bootAppendWhiteBox);
72+
bootAppendWhiteBox,
73+
"-Xlog:cds+class=debug");
7374

7475
TestCommon.run("-cp", app1Jar + File.pathSeparator + app2Jar,
7576
"-XX:+UnlockDiagnosticVMOptions",

0 commit comments

Comments
 (0)
Please sign in to comment.