diff options
author | 2024-08-29 12:57:14 +0000 | |
---|---|---|
committer | 2024-09-24 10:15:56 +0000 | |
commit | 63b8399f3f144769260d93a7a985233e5ac5b910 (patch) | |
tree | 2d46e0d91f2df79a80f9ed80cdcb49c08e7de9f6 /runtime/class_linker.cc | |
parent | 0b8cc45c57bd0d13901e2c1d15f74c8b562fb2d2 (diff) |
Add more validation for const-method-handle.
Making it closer to JVMS 4.4.8 and 5.4.3.5. The RI rejects certain
constructions at the class verification stage, hence there are
separate classes for MethodHandle-s targeting <init> and <clinit>
methods. In these cases The RI throws ClassFormatError during class
load, but currently we do validations only when actual MethodHandle
object is constructed, that's is the reason why test code has
ICCE | CFE in catch blocks. That will be addressed in the
upcoming CLs.
This should not cause any compat issues as even if some of these
MethodHandle were constructed successfully, their invocation
leads to runtime crashes.
Bug: 297147201
Test: ./art/test/testrunner/testrunner.py --host --64 --jvm -b
Change-Id: I551b04e3c00ffc8bcdeac4760d9ac4b3bb7b2aff
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 69 |
1 files changed, 45 insertions, 24 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 2d1bf6f780..c7fbf59420 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -66,12 +66,14 @@ #include "class_loader_utils.h" #include "class_root-inl.h" #include "class_table-inl.h" +#include "common_throws.h" #include "compiler_callbacks.h" #include "debug_print.h" #include "debugger.h" #include "dex/class_accessor-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" +#include "dex/dex_file.h" #include "dex/dex_file_annotations.h" #include "dex/dex_file_exception_helpers.h" #include "dex/dex_file_loader.h" @@ -10338,6 +10340,12 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForField( ThrowIllegalAccessErrorField(referring_class, target_field); return nullptr; } + // TODO(b/364876321): ResolveField might return instance field when is_static is true and + // vice versa. + if (UNLIKELY(is_static != target_field->IsStatic())) { + ThrowIncompatibleClassChangeErrorField(target_field, is_static, referrer); + return nullptr; + } if (UNLIKELY(is_put && target_field->IsFinal())) { ThrowIllegalAccessErrorField(referring_class, target_field); return nullptr; @@ -10430,19 +10438,21 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForMethod( case DexFile::MethodHandleType::kInvokeStatic: { kind = mirror::MethodHandle::Kind::kInvokeStatic; receiver_count = 0; - target_method = ResolveMethod<ResolveMode::kNoChecks>(self, - method_handle.field_or_method_idx_, - referrer, - InvokeType::kStatic); + target_method = + ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self, + method_handle.field_or_method_idx_, + referrer, + InvokeType::kStatic); break; } case DexFile::MethodHandleType::kInvokeInstance: { kind = mirror::MethodHandle::Kind::kInvokeVirtual; receiver_count = 1; - target_method = ResolveMethod<ResolveMode::kNoChecks>(self, - method_handle.field_or_method_idx_, - referrer, - InvokeType::kVirtual); + target_method = + ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self, + method_handle.field_or_method_idx_, + referrer, + InvokeType::kVirtual); break; } case DexFile::MethodHandleType::kInvokeConstructor: { @@ -10450,10 +10460,11 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForMethod( // are special cased later in this method. kind = mirror::MethodHandle::Kind::kInvokeTransform; receiver_count = 0; - target_method = ResolveMethod<ResolveMode::kNoChecks>(self, - method_handle.field_or_method_idx_, - referrer, - InvokeType::kDirect); + target_method = + ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self, + method_handle.field_or_method_idx_, + referrer, + InvokeType::kDirect); break; } case DexFile::MethodHandleType::kInvokeDirect: { @@ -10475,16 +10486,18 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForMethod( if (target_method->IsPrivate()) { kind = mirror::MethodHandle::Kind::kInvokeDirect; - target_method = ResolveMethod<ResolveMode::kNoChecks>(self, - method_handle.field_or_method_idx_, - referrer, - InvokeType::kDirect); + target_method = + ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self, + method_handle.field_or_method_idx_, + referrer, + InvokeType::kDirect); } else { kind = mirror::MethodHandle::Kind::kInvokeSuper; - target_method = ResolveMethod<ResolveMode::kNoChecks>(self, - method_handle.field_or_method_idx_, - referrer, - InvokeType::kSuper); + target_method = + ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self, + method_handle.field_or_method_idx_, + referrer, + InvokeType::kSuper); if (UNLIKELY(target_method == nullptr)) { break; } @@ -10500,10 +10513,11 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForMethod( case DexFile::MethodHandleType::kInvokeInterface: { kind = mirror::MethodHandle::Kind::kInvokeInterface; receiver_count = 1; - target_method = ResolveMethod<ResolveMode::kNoChecks>(self, - method_handle.field_or_method_idx_, - referrer, - InvokeType::kInterface); + target_method = + ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self, + method_handle.field_or_method_idx_, + referrer, + InvokeType::kInterface); break; } } @@ -10513,6 +10527,13 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForMethod( return nullptr; } + // According to JVMS 4.4.8 none of invoke* MethodHandle-s can target <clinit> methods. + if (UNLIKELY(target_method->IsClassInitializer())) { + ThrowClassFormatError(referrer->GetDeclaringClass(), + "Method handles can't target class initializer method"); + return nullptr; + } + ObjPtr<mirror::Class> target_class = target_method->GetDeclaringClass(); ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); uint32_t access_flags = target_method->GetAccessFlags(); |