void ThrowArrayStoreException(ObjPtr<mirror::Class> element_class,
ObjPtr<mirror::Class> array_class) {
ThrowException("Ljava/lang/ArrayStoreException;", nullptr,
StringPrintf("%s cannot be stored in an array of type %s",
mirror::Class::PrettyDescriptor(element_class).c_str(),
mirror::Class::PrettyDescriptor(array_class).c_str()).c_str());
}
void ThrowIllegalAccessErrorForImplementingMethod(ObjPtr<mirror::Class> klass,
ArtMethod* implementation_method,
ArtMethod* interface_method)
REQUIRES_SHARED(Locks::mutator_lock_) { // Note: For a non-public abstract implementing method, both `AbstractMethodError` and // `IllegalAccessError` are reasonable. We now follow the RI behaviour and throw the latter, // so we do not assert here that the implementation method is concrete as we did in the past.
DCHECK(!implementation_method->IsPublic());
ThrowIllegalAccessError(
klass, "Method '%s' implementing interface method '%s' is not public",
implementation_method->PrettyMethod().c_str(),
interface_method->PrettyMethod().c_str());
}
void ThrowIncompatibleClassChangeError(InvokeType expected_type,
InvokeType found_type,
ArtMethod* method,
ArtMethod* referrer) {
std::ostringstream msg;
msg << "The method '" << ArtMethod::PrettyMethod(method) << "' was expected to be of type "
<< expected_type << " but instead was found to be of type " << found_type;
ThrowException("Ljava/lang/IncompatibleClassChangeError;",
referrer != nullptr ? referrer->GetDeclaringClass() : nullptr,
msg.str().c_str());
}
void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(ArtMethod* interface_method,
ObjPtr<mirror::Object> this_object,
ArtMethod* referrer) { // Referrer is calling interface_method on this_object, however, the interface_method isn't // implemented by this_object.
CHECK(this_object != nullptr);
std::ostringstream msg;
msg << "Class '" << mirror::Class::PrettyDescriptor(this_object->GetClass())
<< "' does not implement interface '"
<< mirror::Class::PrettyDescriptor(interface_method->GetDeclaringClass())
<< "' in call to '" << ArtMethod::PrettyMethod(interface_method) << "'";
ThrowException("Ljava/lang/IncompatibleClassChangeError;",
referrer != nullptr ? referrer->GetDeclaringClass() : nullptr,
msg.str().c_str());
}
void ThrowIncompatibleClassChangeErrorField(ArtField* resolved_field, bool is_static,
ArtMethod* referrer) {
std::ostringstream msg;
msg << "Expected '" << ArtField::PrettyField(resolved_field) << "' to be a "
<< (is_static ? "static" : "instance") << " field" << " rather than a "
<< (is_static ? "instance" : "static") << " field";
ThrowException("Ljava/lang/IncompatibleClassChangeError;", referrer->GetDeclaringClass(),
msg.str().c_str());
}
switch (instr.Opcode()) { case Instruction::INVOKE_DIRECT: case Instruction::INVOKE_DIRECT_RANGE: case Instruction::INVOKE_VIRTUAL: case Instruction::INVOKE_VIRTUAL_RANGE: case Instruction::INVOKE_INTERFACE: case Instruction::INVOKE_INTERFACE_RANGE: case Instruction::INVOKE_POLYMORPHIC: case Instruction::INVOKE_POLYMORPHIC_RANGE: case Instruction::INVOKE_SUPER: case Instruction::INVOKE_SUPER_RANGE: { // Without inlining, we could just check that the offset is the class offset. // However, when inlining, the compiler can (validly) merge the null check with a field access // on the same object. Note that the stack map at the NPE will reflect the invoke's location, // which is the caller. returntrue;
}
case Instruction::IGET_OBJECT: if (gUseReadBarrier && IsValidReadBarrierImplicitCheck(addr)) { returntrue;
}
FALLTHROUGH_INTENDED; case Instruction::IGET: case Instruction::IGET_WIDE: case Instruction::IGET_BOOLEAN: case Instruction::IGET_BYTE: case Instruction::IGET_CHAR: case Instruction::IGET_SHORT: case Instruction::IPUT: case Instruction::IPUT_WIDE: case Instruction::IPUT_OBJECT: case Instruction::IPUT_BOOLEAN: case Instruction::IPUT_BYTE: case Instruction::IPUT_CHAR: case Instruction::IPUT_SHORT: { // We might be doing an implicit null check with an offset that doesn't correspond // to the instruction, for example with two field accesses and the first one being // eliminated or re-ordered. returntrue;
}
case Instruction::AGET_OBJECT: if (gUseReadBarrier && IsValidReadBarrierImplicitCheck(addr)) { returntrue;
}
FALLTHROUGH_INTENDED; case Instruction::AGET: case Instruction::AGET_WIDE: case Instruction::AGET_BOOLEAN: case Instruction::AGET_BYTE: case Instruction::AGET_CHAR: case Instruction::AGET_SHORT: case Instruction::APUT: case Instruction::APUT_WIDE: case Instruction::APUT_OBJECT: case Instruction::APUT_BOOLEAN: case Instruction::APUT_BYTE: case Instruction::APUT_CHAR: case Instruction::APUT_SHORT: case Instruction::FILL_ARRAY_DATA: case Instruction::ARRAY_LENGTH: { // The length access should crash. We currently do not do implicit checks on // the array access itself. return (addr == 0u) || (addr == mirror::Array::LengthOffset().Uint32Value());
}
default: { // We have covered all the cases where an NPE could occur. // Note that this must be kept in sync with the compiler, and adding // any new way to do implicit checks in the compiler should also update // this code. returnfalse;
}
}
}
switch (instr.Opcode()) { case Instruction::INVOKE_DIRECT:
ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kDirect); break; case Instruction::INVOKE_DIRECT_RANGE:
ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kDirect); break; case Instruction::INVOKE_VIRTUAL:
ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kVirtual); break; case Instruction::INVOKE_VIRTUAL_RANGE:
ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kVirtual); break; case Instruction::INVOKE_SUPER:
ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kSuper); break; case Instruction::INVOKE_SUPER_RANGE:
ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kSuper); break; case Instruction::INVOKE_INTERFACE:
ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kInterface); break; case Instruction::INVOKE_INTERFACE_RANGE:
ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kInterface); break; case Instruction::INVOKE_POLYMORPHIC:
ThrowNullPointerExceptionForMethodAccess(instr.VRegB_45cc(), kVirtual); break; case Instruction::INVOKE_POLYMORPHIC_RANGE:
ThrowNullPointerExceptionForMethodAccess(instr.VRegB_4rcc(), kVirtual); break; case Instruction::IGET: case Instruction::IGET_WIDE: case Instruction::IGET_OBJECT: case Instruction::IGET_BOOLEAN: case Instruction::IGET_BYTE: case Instruction::IGET_CHAR: case Instruction::IGET_SHORT: {
ArtField* field =
Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false);
Thread::Current()->ClearException(); // Resolution may fail, ignore.
ThrowNullPointerExceptionForFieldAccess(field, method, /* is_read= */ true); break;
} case Instruction::IPUT: case Instruction::IPUT_WIDE: case Instruction::IPUT_OBJECT: case Instruction::IPUT_BOOLEAN: case Instruction::IPUT_BYTE: case Instruction::IPUT_CHAR: case Instruction::IPUT_SHORT: {
ArtField* field = Runtime::Current()->GetClassLinker()->ResolveField(
instr.VRegC_22c(), method, /* is_static= */ false);
Thread::Current()->ClearException(); // Resolution may fail, ignore.
ThrowNullPointerExceptionForFieldAccess(field, method, /* is_read= */ false); break;
} case Instruction::AGET: case Instruction::AGET_WIDE: case Instruction::AGET_OBJECT: case Instruction::AGET_BOOLEAN: case Instruction::AGET_BYTE: case Instruction::AGET_CHAR: case Instruction::AGET_SHORT:
ThrowException("Ljava/lang/NullPointerException;", nullptr, "Attempt to read from null array"); break; case Instruction::APUT: case Instruction::APUT_WIDE: case Instruction::APUT_OBJECT: case Instruction::APUT_BOOLEAN: case Instruction::APUT_BYTE: case Instruction::APUT_CHAR: case Instruction::APUT_SHORT:
ThrowException("Ljava/lang/NullPointerException;", nullptr, "Attempt to write to null array"); break; case Instruction::ARRAY_LENGTH:
ThrowException("Ljava/lang/NullPointerException;", nullptr, "Attempt to get length of null array"); break; case Instruction::FILL_ARRAY_DATA: {
ThrowException("Ljava/lang/NullPointerException;", nullptr, "Attempt to write to null array"); break;
} case Instruction::MONITOR_ENTER: case Instruction::MONITOR_EXIT: {
ThrowException("Ljava/lang/NullPointerException;", nullptr, "Attempt to do a synchronize operation on a null object"); break;
} default: { const DexFile* dex_file = method->GetDexFile();
LOG(FATAL) << "NullPointerException at an unexpected instruction: "
<< instr.DumpString(dex_file)
<< " in "
<< method->PrettyMethod();
UNREACHABLE();
}
}
}
template <StackType stack_type> void ThrowStackOverflowError(Thread* self) { if (self->IsHandlingStackOverflow<stack_type>()) {
LOG(ERROR) << "Recursive stack overflow."; // We don't fail here because SetStackEndForStackOverflow will print better diagnostics.
}
// Allow space on the stack for constructor to execute.
self->SetStackEndForStackOverflow<stack_type>();
// Remove the stack overflow protection if it is set up. bool implicit_stack_check = Runtime::Current()->GetImplicitStackOverflowChecks(); if (implicit_stack_check) { if (!self->UnprotectStack<stack_type>()) {
LOG(ERROR) << "Unable to remove stack protection for stack overflow";
}
}
// Avoid running Java code for exception initialization. // TODO: Checks to make this a bit less brittle. // // Note: This lambda is used to make sure the `StackOverflowError` intitialization code // does not increase the frame size of `ThrowStackOverflowError()` itself. It runs // with its own frame in the extended stack, which is especially important for modes // with larger stack sizes (e.g., ASAN). auto create_and_throw = [self]() REQUIRES_SHARED(Locks::mutator_lock_) NO_INLINE {
std::string msg("stack size ");
msg += PrettySize(self->GetUsableStackSize<stack_type>());
// stackState is set as result of fillInStackTrace. fillInStackTrace calls // nativeFillInStackTrace.
ObjPtr<mirror::Object> stack_state_val = self->CreateInternalStackTrace(soa); if (stack_state_val != nullptr) {
WellKnownClasses::java_lang_Throwable_stackState
->SetObject</*kTransactionActive=*/ false>(exc.Get(), stack_state_val);
// stackTrace.
ObjPtr<mirror::Class> l_u_ea = WellKnownClasses::libcore_util_EmptyArray.Get();
DCHECK(l_u_ea->IsInitialized());
ObjPtr<mirror::Object> empty_ste =
WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT->GetObject(l_u_ea);
CHECK(empty_ste != nullptr);
WellKnownClasses::java_lang_Throwable_stackTrace
->SetObject</*kTransactionActive=*/ false>(exc.Get(), empty_ste);
} else {
LOG(WARNING) << "Could not create stack trace."; // Note: we'll create an exception without stack state, which is valid.
}
// Throw the exception.
self->SetException(exc->AsThrowable());
};
create_and_throw();
CHECK(self->IsExceptionPending());
self->ResetDefaultStackEnd<stack_type>(); // Return to default stack size.
// And restore protection if implicit checks are on. if (implicit_stack_check) {
self->ProtectStack<stack_type>();
}
}
// Explicit instantiations to keep this definition separate to the declaration. templatevoid ThrowStackOverflowError<StackType::kHardware>(Thread* self); #ifdef ART_USE_SIMULATOR templatevoid ThrowStackOverflowError<StackType::kSimulated>(Thread* self); #endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.