< prev index next >
src/hotspot/share/oops/instanceKlass.cpp
Print this page
*** 148,167 ****
// called to verify that k is a member of this nest
bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
if (_nest_members == NULL || _nest_members == Universe::the_empty_short_array()) {
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
! log_trace(class, nestmates)("Checking nest membership of %s in non-nest-host class %s",
! k->name()->as_C_string(), this->name()->as_C_string());
}
return false;
}
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Checking nest membership of %s in %s",
! k->name()->as_C_string(), this->name()->as_C_string());
}
// Check names first and if they match then check actual klass. This avoids
// resolving anything unnecessarily.
for (int i = 0; i < _nest_members->length(); i++) {
--- 148,167 ----
// called to verify that k is a member of this nest
bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
if (_nest_members == NULL || _nest_members == Universe::the_empty_short_array()) {
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
! log_trace(class, nestmates)("Checked nest membership of %s in non-nest-host class %s",
! k->external_name(), this->external_name());
}
return false;
}
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Checking nest membership of %s in %s",
! k->external_name(), this->external_name());
}
// Check names first and if they match then check actual klass. This avoids
// resolving anything unnecessarily.
for (int i = 0; i < _nest_members->length(); i++) {
*** 172,291 ****
// names match so check actual klass - this may trigger class loading if
// it doesn't match (but that should be impossible)
Klass* k2 = _constants->klass_at(cp_index, CHECK_false);
if (k2 == k) {
! log_trace(class, nestmates)("- klass is nestmate member");
return true;
}
else {
// same name but different klass!
log_trace(class, nestmates)(" - klass comparison failed!");
}
}
}
! log_trace(class, nestmates)("- klass is NOT nestmate member!");
return false;
}
! // Return nest-host class, resolving, validating and saving it if needed
InstanceKlass* InstanceKlass::nest_host(TRAPS) {
InstanceKlass* nest_host_k = _nest_host;
if (nest_host_k == NULL) {
// need to resolve and save our nest-host class. This could be attempted
// concurrently but as the result is idempotent and we don't use the class
// then we do not need any synchronization beyond what is implicitly used
// during class loading.
if (_nest_host_index != 0) { // we have a real nest_host
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
! log_trace(class, nestmates)("Resolving nest-host of %s using cp entry for %s",
! this->name()->as_C_string(),
! _constants->klass_name_at(_nest_host_index)->as_C_string());
}
-
- Klass* k = _constants->klass_at(_nest_host_index, CHECK_NULL);
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
! log_trace(class, nestmates)("Resolved nest-host of %s to %s",
! this->name()->as_C_string(), k->name()->as_C_string());
}
! if (!k->is_instance_klass()) {
! ResourceMark rm(THREAD);
! Exceptions::fthrow(
! THREAD_AND_LOCATION,
! vmSymbols::java_lang_IncompatibleClassChangeError(),
! "class %s has non-instance class %s as nest-host",
! this->external_name(),
! k->external_name()
! );
return NULL;
}
nest_host_k = InstanceKlass::cast(k);
bool is_member = nest_host_k->has_nest_member(this, CHECK_NULL);
! if (!is_member) {
! // this_k and nest_host disagree about nest membership
ResourceMark rm(THREAD);
! Exceptions::fthrow(
! THREAD_AND_LOCATION,
! vmSymbols::java_lang_IncompatibleClassChangeError(),
! "Type %s is not a nest member of %s",
this->external_name(),
! nest_host_k->external_name()
! );
! return NULL;
}
- if (!is_same_class_package(nest_host_k)) {
ResourceMark rm(THREAD);
! Exceptions::fthrow(
! THREAD_AND_LOCATION,
! vmSymbols::java_lang_IncompatibleClassChangeError(),
! "Class %s is in a different package to its nest-host class %s",
this->external_name(),
! nest_host_k->external_name()
);
return NULL;
}
- }
else {
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
! log_trace(class, nestmates)("Class %s is not part of a nest: setting nest-host to self",
! this->name()->as_C_string());
}
! nest_host_k = const_cast<InstanceKlass*>(this);
}
}
- // save resolved nest-host value
- _nest_host = nest_host_k;
-
return nest_host_k;
}
// check if 'this' and k are nestmates (same nest_host), or k is our nest_host,
// or we are k's nest_host - all of which is covered by comparing the two
// resolved_nest_hosts
bool InstanceKlass::has_nestmate_access_to(InstanceKlass* k, TRAPS) {
! // If not actually nestmates, then both nest-host classes may have to loaded
! // and the nest membership of each class validated.
! InstanceKlass* cur_top = nest_host(CHECK_false);
! Klass* k_nest_host = k->nest_host(CHECK_false);
! bool access = (cur_top == k_nest_host);
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Class %s does %shave nestmate accesss to %s",
! this->name()->as_C_string(),
access ? "" : "NOT ",
! k->name()->as_C_string());
}
return access;
}
--- 172,341 ----
// names match so check actual klass - this may trigger class loading if
// it doesn't match (but that should be impossible)
Klass* k2 = _constants->klass_at(cp_index, CHECK_false);
if (k2 == k) {
! log_trace(class, nestmates)("- class is listed as a nest member");
return true;
}
else {
// same name but different klass!
log_trace(class, nestmates)(" - klass comparison failed!");
}
}
}
! log_trace(class, nestmates)("- class is NOT a nest member!");
return false;
}
! // Return nest-host class, resolving, validating and saving it if needed.
! // In cases where this is called from a thread that can not do classloading
! // (such as a native JIT thread) then we simply return NULL, which in turn
! // causes the access check to return false. Such code will retry the access
! // from a more suitable environment later.
InstanceKlass* InstanceKlass::nest_host(TRAPS) {
InstanceKlass* nest_host_k = _nest_host;
if (nest_host_k == NULL) {
// need to resolve and save our nest-host class. This could be attempted
// concurrently but as the result is idempotent and we don't use the class
// then we do not need any synchronization beyond what is implicitly used
// during class loading.
if (_nest_host_index != 0) { // we have a real nest_host
+ // Before trying to resolve check if we're in a suitable context
+ if (!THREAD->can_call_java() && !_constants->tag_at(_nest_host_index).is_klass()) {
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
! log_trace(class, nestmates)("Rejected resolution of nest-host of %s in unsuitable thread",
! this->external_name());
! }
! return NULL;
}
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
! log_trace(class, nestmates)("Resolving nest-host of %s using cp entry for %s",
! this->external_name(),
! _constants->klass_name_at(_nest_host_index)->as_C_string());
}
! Klass* k = _constants->klass_at(_nest_host_index, THREAD);
! if (HAS_PENDING_EXCEPTION) {
! Handle exc_h = Handle(THREAD, PENDING_EXCEPTION);
! if (exc_h->is_a(SystemDictionary::NoClassDefFoundError_klass())) {
! // throw a new CDNFE with the original as its cause, and a clear msg
! ResourceMark rm(THREAD);
! char buf[200];
! CLEAR_PENDING_EXCEPTION;
! jio_snprintf(buf, sizeof(buf),
! "Unable to load nest-host class of %s",
! this->external_name());
! log_trace(class, nestmates)("%s - NoClassDefFoundError", buf);
! THROW_MSG_CAUSE_NULL(vmSymbols::java_lang_NoClassDefFoundError(), buf, exc_h);
! }
! // other exceptions pass through (OOME, StackOverflowError etc)
return NULL;
}
+ // A valid nest-host is an instance class in the current package that lists this
+ // class as a nest member. If any of these conditions are not met we simply throw
+ // IllegalAccessError, with a suitable message.
+
+ const char* error = NULL;
+
+ // Need to check we have an instance class first
+ if (k->is_instance_klass()) {
nest_host_k = InstanceKlass::cast(k);
+ // FIXME: an exception from this is perhaps impossible
bool is_member = nest_host_k->has_nest_member(this, CHECK_NULL);
! if (is_member) {
! // Finally check we're in the same package - as there could be collusion
! // between untrusted types.
! if (is_same_class_package(nest_host_k)) {
! // save resolved nest-host value
! _nest_host = nest_host_k;
!
! if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
! log_trace(class, nestmates)("Resolved nest-host of %s to %s",
! this->external_name(), k->external_name());
! }
! return nest_host_k;
! }
! else {
! error = "types are in different packages";
! }
! }
! else {
! error = "current type is not listed as a nest member";
! }
! }
! else {
! error = "nest-host is not an instance class!";
! }
!
! if (log_is_enabled(Trace, class, nestmates)) {
! ResourceMark rm(THREAD);
! log_trace(class, nestmates)("Type %s is not a nest member of resolved type %s: %s",
this->external_name(),
! k->external_name(),
! error);
}
ResourceMark rm(THREAD);
! Exceptions::fthrow(THREAD_AND_LOCATION,
! vmSymbols::java_lang_IllegalAccessError(),
! "Type %s is not a nest member of %s: %s",
this->external_name(),
! k->external_name(),
! error
);
return NULL;
}
else {
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
! log_trace(class, nestmates)("Type %s is not part of a nest: setting nest-host to self",
! this->external_name());
}
! // save resolved nest-host value
! return (_nest_host = this);
}
}
return nest_host_k;
}
// check if 'this' and k are nestmates (same nest_host), or k is our nest_host,
// or we are k's nest_host - all of which is covered by comparing the two
// resolved_nest_hosts
bool InstanceKlass::has_nestmate_access_to(InstanceKlass* k, TRAPS) {
! assert(this != k, "this should be handled by higher-level code");
!
! // Per the JVMS we first resolve and validate the current class, then
! // the target class k. Resolution exceptions will be passed on by upper
! // layers. IllegalAccessErrors from membership validation failures will
! // also be passed through.
!
! InstanceKlass* cur_host = nest_host(THREAD);
! if (cur_host == NULL || HAS_PENDING_EXCEPTION) {
! return false;
! }
!
! Klass* k_nest_host = k->nest_host(THREAD);
! if (k_nest_host == NULL || HAS_PENDING_EXCEPTION) {
! return false;
! }
! bool access = (cur_host == k_nest_host);
if (log_is_enabled(Trace, class, nestmates)) {
ResourceMark rm(THREAD);
log_trace(class, nestmates)("Class %s does %shave nestmate accesss to %s",
! this->external_name(),
access ? "" : "NOT ",
! k->external_name());
}
return access;
}
< prev index next >