From cfa325e4ca65603fdb03a836a6cb394d23ed511f Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Thu, 13 Oct 2016 10:25:54 +0100 Subject: [PATCH] ART: Add verifier support for invoke-polymorphic. Change-Id: I1e1860cad80db46320c3ef5a9eaceb7529ea68d7 Bug: 30550796,33099829,33191712 Test: make test-art-host --- runtime/art_method.h | 4 + runtime/dex_instruction.h | 5 + runtime/dex_instruction_list.h | 4 +- runtime/interpreter/interpreter_common.cc | 5 - runtime/mirror/method_handle_impl.cc | 6 + runtime/mirror/method_handle_impl.h | 2 + runtime/verifier/method_verifier.cc | 194 +++++++++++++++++---- runtime/verifier/method_verifier.h | 13 +- runtime/verifier/register_line.cc | 7 +- runtime/verifier/register_line.h | 1 - test/954-invoke-polymorphic-verifier/build | 25 +++ test/954-invoke-polymorphic-verifier/check | 19 ++ test/954-invoke-polymorphic-verifier/expected.txt | 10 ++ test/954-invoke-polymorphic-verifier/info.txt | 3 + test/954-invoke-polymorphic-verifier/run | 20 +++ .../smali/BadThis.smali | 30 ++++ .../smali/BetterFakeSignaturePolymorphic.smali | 43 +++++ .../smali/FakeSignaturePolymorphic.smali | 43 +++++ .../smali/Main.smali | 85 +++++++++ .../smali/MethodHandleNotInvoke.smali | 37 ++++ .../smali/MethodHandleToString.smali | 35 ++++ .../smali/NonReference.smali | 30 ++++ .../smali/Subclass.smali | 45 +++++ .../smali/TooFewArguments.smali | 33 ++++ .../smali/TooManyArguments.smali | 35 ++++ .../smali/Unresolved.smali | 40 +++++ 26 files changed, 724 insertions(+), 50 deletions(-) create mode 100755 test/954-invoke-polymorphic-verifier/build create mode 100755 test/954-invoke-polymorphic-verifier/check create mode 100644 test/954-invoke-polymorphic-verifier/expected.txt create mode 100644 test/954-invoke-polymorphic-verifier/info.txt create mode 100755 test/954-invoke-polymorphic-verifier/run create mode 100644 test/954-invoke-polymorphic-verifier/smali/BadThis.smali create mode 100644 test/954-invoke-polymorphic-verifier/smali/BetterFakeSignaturePolymorphic.smali create mode 100644 test/954-invoke-polymorphic-verifier/smali/FakeSignaturePolymorphic.smali create mode 100644 test/954-invoke-polymorphic-verifier/smali/Main.smali create mode 100644 test/954-invoke-polymorphic-verifier/smali/MethodHandleNotInvoke.smali create mode 100644 test/954-invoke-polymorphic-verifier/smali/MethodHandleToString.smali create mode 100644 test/954-invoke-polymorphic-verifier/smali/NonReference.smali create mode 100644 test/954-invoke-polymorphic-verifier/smali/Subclass.smali create mode 100644 test/954-invoke-polymorphic-verifier/smali/TooFewArguments.smali create mode 100644 test/954-invoke-polymorphic-verifier/smali/TooManyArguments.smali create mode 100644 test/954-invoke-polymorphic-verifier/smali/Unresolved.smali diff --git a/runtime/art_method.h b/runtime/art_method.h index 0e1d7e730..daef35dfa 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -245,6 +245,10 @@ class ArtMethod FINAL { return (GetAccessFlags() & kAccSynthetic) != 0; } + bool IsVarargs() { + return (GetAccessFlags() & kAccVarargs) != 0; + } + template bool IsProxyMethod() REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h index 99b9f9dd1..578550cae 100644 --- a/runtime/dex_instruction.h +++ b/runtime/dex_instruction.h @@ -189,6 +189,7 @@ class Instruction { kVerifyVarArgRangeNonZero = 0x100000, kVerifyRuntimeOnly = 0x200000, kVerifyError = 0x400000, + kVerifyRegHPrototype = 0x800000 }; static constexpr uint32_t kMaxVarArgRegs = 5; @@ -579,6 +580,10 @@ class Instruction { kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide)); } + int GetVerifyTypeArgumentH() const { + return (kInstructionVerifyFlags[Opcode()] & kVerifyRegHPrototype); + } + int GetVerifyExtraFlags() const { return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget | kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgNonZero | kVerifyVarArgRange | diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h index e537afe31..ca2ce1d99 100644 --- a/runtime/dex_instruction_list.h +++ b/runtime/dex_instruction_list.h @@ -269,8 +269,8 @@ V(0xF7, UNUSED_F7, "unused-f7", k10x, kIndexUnknown, 0, kVerifyError) \ V(0xF8, UNUSED_F8, "unused-f8", k10x, kIndexUnknown, 0, kVerifyError) \ V(0xF9, UNUSED_F9, "unused-f9", k10x, kIndexUnknown, 0, kVerifyError) \ - V(0xFA, INVOKE_POLYMORPHIC, "invoke-polymorphic", k45cc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero | kExperimental) \ - V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero | kExperimental) \ + V(0xFA, INVOKE_POLYMORPHIC, "invoke-polymorphic", k45cc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero | kVerifyRegHPrototype) \ + V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero | kVerifyRegHPrototype) \ V(0xFC, UNUSED_FC, "unused-fc", k10x, kIndexUnknown, 0, kVerifyError) \ V(0xFD, UNUSED_FD, "unused-fd", k10x, kIndexUnknown, 0, kVerifyError) \ V(0xFE, UNUSED_FE, "unused-fe", k10x, kIndexUnknown, 0, kVerifyError) \ diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 72dbe6aac..22da07dd2 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -865,11 +865,6 @@ inline bool DoInvokePolymorphic(Thread* self, // The invoke_method_idx here is the name of the signature polymorphic method that // was symbolically invoked in bytecode (say MethodHandle.invoke or MethodHandle.invokeExact) // and not the method that we'll dispatch to in the end. - // - // TODO(narayan) We'll have to check in the verifier that this is in fact a - // signature polymorphic method so that we disallow calls via invoke-polymorphic - // to non sig-poly methods. This would also have the side effect of verifying - // that vRegC really is a reference type. StackHandleScope<6> hs(self); Handle method_handle(hs.NewHandle( ObjPtr::DownCast( diff --git a/runtime/mirror/method_handle_impl.cc b/runtime/mirror/method_handle_impl.cc index fdfaaa8ca..4f1c448b5 100644 --- a/runtime/mirror/method_handle_impl.cc +++ b/runtime/mirror/method_handle_impl.cc @@ -22,6 +22,12 @@ namespace art { namespace mirror { +mirror::Class* MethodHandle::StaticClass() { + mirror::Class* klass = MethodHandleImpl::StaticClass()->GetSuperClass(); + DCHECK(klass->DescriptorEquals("Ljava/lang/invoke/MethodHandle;")); + return klass; +} + GcRoot MethodHandleImpl::static_class_; void MethodHandleImpl::SetClass(Class* klass) { diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h index 905421606..5ea82b535 100644 --- a/runtime/mirror/method_handle_impl.h +++ b/runtime/mirror/method_handle_impl.h @@ -57,6 +57,8 @@ class MANAGED MethodHandle : public Object { return static_cast(handle_kind); } + static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); + private: HeapReference nominal_type_; HeapReference method_type_; diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 7137db877..38cc35c8e 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -41,6 +41,7 @@ #include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" +#include "mirror/method_handle_impl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "reg_type-inl.h" @@ -1184,6 +1185,11 @@ bool MethodVerifier::VerifyInstruction(const Instruction* inst, uint32_t code_of result = result && CheckWideRegisterIndex(inst->VRegC()); break; } + switch (inst->GetVerifyTypeArgumentH()) { + case Instruction::kVerifyRegHPrototype: + result = result && CheckPrototypeIndex(inst->VRegH()); + break; + } switch (inst->GetVerifyExtraFlags()) { case Instruction::kVerifyArrayData: result = result && CheckArrayData(code_offset); @@ -1289,6 +1295,15 @@ inline bool MethodVerifier::CheckNewInstance(dex::TypeIndex idx) { return true; } +inline bool MethodVerifier::CheckPrototypeIndex(uint32_t idx) { + if (idx >= dex_file_->GetHeader().proto_ids_size_) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad prototype index " << idx << " (max " + << dex_file_->GetHeader().proto_ids_size_ << ")"; + return false; + } + return true; +} + inline bool MethodVerifier::CheckStringIndex(uint32_t idx) { if (idx >= dex_file_->GetHeader().string_ids_size_) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad string index " << idx << " (max " @@ -2934,7 +2949,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { * allowing the latter only if the "this" argument is the same as the "this" argument to * this method (which implies that we're in a constructor ourselves). */ - const RegType& this_type = work_line_->GetInvocationThis(this, inst, is_range); + const RegType& this_type = work_line_->GetInvocationThis(this, inst); if (this_type.IsConflict()) // failure. break; @@ -3015,7 +3030,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { /* Get the type of the "this" arg, which should either be a sub-interface of called * interface or Object (see comments in RegType::JoinClass). */ - const RegType& this_type = work_line_->GetInvocationThis(this, inst, is_range); + const RegType& this_type = work_line_->GetInvocationThis(this, inst); if (this_type.IsZero()) { /* null pointer always passes (and always fails at runtime) */ } else { @@ -3057,10 +3072,37 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { } case Instruction::INVOKE_POLYMORPHIC: case Instruction::INVOKE_POLYMORPHIC_RANGE: { + bool is_range = (inst->Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE); + ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_POLYMORPHIC, is_range); + if (called_method == nullptr) { + // Convert potential soft failures in VerifyInvocationArgs() to hard errors. + if (failure_messages_.size() > 0) { + std::string message = failure_messages_.back()->str(); + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << message; + } else { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke-polymorphic verification failure."; + } + break; + } + if (!CheckSignaturePolymorphicMethod(called_method) || + !CheckSignaturePolymorphicReceiver(inst)) { + break; + } + const uint32_t proto_idx = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc(); + const char* descriptor = + dex_file_->GetReturnTypeDescriptor(dex_file_->GetProtoId(proto_idx)); + const RegType& return_type = + reg_types_.FromDescriptor(GetClassLoader(), descriptor, false); + if (!return_type.IsLowHalf()) { + work_line_->SetResultRegisterType(this, return_type); + } else { + work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(®_types_)); + } + // TODO(oth): remove when compiler support is available. Fail(VERIFY_ERROR_FORCE_INTERPRETER) - << "instruction is not supported by verifier; skipping verification"; + << "invoke-polymorphic is not supported by compiler"; have_pending_experimental_failure_ = true; - return false; + break; } case Instruction::NEG_INT: case Instruction::NOT_INT: @@ -3416,8 +3458,6 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { work_line_->SetResultTypeToUnknown(this); } - - /* * Handle "branch". Tag the branch target. * @@ -3740,7 +3780,8 @@ inline static MethodResolutionKind GetMethodResolutionKind( } else if (method_type == METHOD_SUPER && is_interface) { return kInterfaceMethodResolution; } else { - DCHECK(method_type == METHOD_VIRTUAL || method_type == METHOD_SUPER); + DCHECK(method_type == METHOD_VIRTUAL || method_type == METHOD_SUPER + || method_type == METHOD_POLYMORPHIC); return kVirtualMethodResolution; } } @@ -3868,15 +3909,18 @@ ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess( return nullptr; } // See if the method type implied by the invoke instruction matches the access flags for the - // target method. + // target method. The flags for METHOD_POLYMORPHIC are based on there being precisely two + // signature polymorphic methods supported by the run-time which are native methods with variable + // arguments. if ((method_type == METHOD_DIRECT && (!res_method->IsDirect() || res_method->IsStatic())) || (method_type == METHOD_STATIC && !res_method->IsStatic()) || ((method_type == METHOD_SUPER || method_type == METHOD_VIRTUAL || - method_type == METHOD_INTERFACE) && res_method->IsDirect()) - ) { + method_type == METHOD_INTERFACE) && res_method->IsDirect()) || + ((method_type == METHOD_POLYMORPHIC) && + (!res_method->IsNative() || !res_method->IsVarargs()))) { Fail(VERIFY_ERROR_CLASS_CHANGE) << "invoke type (" << method_type << ") does not match method " - " type of " << res_method->PrettyMethod(); + "type of " << res_method->PrettyMethod(); return nullptr; } return res_method; @@ -3888,20 +3932,18 @@ ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator( // We use vAA as our expected arg count, rather than res_method->insSize, because we need to // match the call to the signature. Also, we might be calling through an abstract method // definition (which doesn't have register count values). - const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c(); + const size_t expected_args = inst->VRegA(); /* caught by static verifier */ DCHECK(is_range || expected_args <= 5); - if (expected_args > code_item_->outs_size_) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args - << ") exceeds outsSize (" << code_item_->outs_size_ << ")"; - return nullptr; - } - uint32_t arg[5]; - if (!is_range) { - inst->GetVarArgs(arg); + // TODO(oth): Enable this path for invoke-polymorphic when b/33099829 is resolved. + if (method_type != METHOD_POLYMORPHIC) { + if (expected_args > code_item_->outs_size_) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args + << ") exceeds outsSize (" << code_item_->outs_size_ << ")"; + return nullptr; + } } - uint32_t sig_registers = 0; /* * Check the "this" argument, which must be an instance of the class that declared the method. @@ -3909,7 +3951,7 @@ ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator( * rigorous check here (which is okay since we have to do it at runtime). */ if (method_type != METHOD_STATIC) { - const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst, is_range); + const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst); if (actual_arg_type.IsConflict()) { // GetInvocationThis failed. CHECK(have_pending_hard_failure_); return nullptr; @@ -3945,7 +3987,7 @@ ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator( res_method_class = &FromClass(klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes()); } else { - const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); + const uint32_t method_idx = inst->VRegB(); const dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_; res_method_class = ®_types_.FromDescriptor( GetClassLoader(), @@ -3965,13 +4007,17 @@ ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator( } } } - sig_registers = 1; } + uint32_t arg[5]; + if (!is_range) { + inst->GetVarArgs(arg); + } + uint32_t sig_registers = (method_type == METHOD_STATIC) ? 0 : 1; for ( ; it->HasNext(); it->Next()) { if (sig_registers >= expected_args) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation, expected " << inst->VRegA() << - " arguments, found " << sig_registers << " or more."; + " argument registers, method signature has " << sig_registers + 1 << " or more"; return nullptr; } @@ -3984,7 +4030,7 @@ ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator( } const RegType& reg_type = reg_types_.FromDescriptor(GetClassLoader(), param_descriptor, false); - uint32_t get_reg = is_range ? inst->VRegC_3rc() + static_cast(sig_registers) : + uint32_t get_reg = is_range ? inst->VRegC() + static_cast(sig_registers) : arg[sig_registers]; if (reg_type.IsIntegralTypes()) { const RegType& src_type = work_line_->GetRegisterType(this, get_reg); @@ -4020,7 +4066,7 @@ ArtMethod* MethodVerifier::VerifyInvocationArgsFromIterator( } if (expected_args != sig_registers) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation, expected " << expected_args << - " arguments, found " << sig_registers; + " argument registers, method signature has " << sig_registers; return nullptr; } return res_method; @@ -4032,11 +4078,10 @@ void MethodVerifier::VerifyInvocationArgsUnresolvedMethod(const Instruction* ins // As the method may not have been resolved, make this static check against what we expect. // The main reason for this code block is to fail hard when we find an illegal use, e.g., // wrong number of arguments or wrong primitive types, even if the method could not be resolved. - const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); + const uint32_t method_idx = inst->VRegB(); DexFileParameterIterator it(*dex_file_, dex_file_->GetProtoId(dex_file_->GetMethodId(method_idx).proto_idx_)); - VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, - nullptr); + VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, nullptr); } class MethodParamListDescriptorIterator { @@ -4069,8 +4114,7 @@ ArtMethod* MethodVerifier::VerifyInvocationArgs( const Instruction* inst, MethodType method_type, bool is_range) { // Resolve the method. This could be an abstract or concrete method depending on what sort of call // we're making. - const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); - + const uint32_t method_idx = inst->VRegB(); ArtMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type); if (res_method == nullptr) { // error or class is unresolved // Check what we can statically. @@ -4133,10 +4177,84 @@ ArtMethod* MethodVerifier::VerifyInvocationArgs( } } - // Process the target method's signature. This signature may or may not - MethodParamListDescriptorIterator it(res_method); - return VerifyInvocationArgsFromIterator(&it, inst, method_type, - is_range, res_method); + if (method_type == METHOD_POLYMORPHIC) { + // Process the signature of the calling site that is invoking the method handle. + DexFileParameterIterator it(*dex_file_, dex_file_->GetProtoId(inst->VRegH())); + return VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method); + } else { + // Process the target method's signature. + MethodParamListDescriptorIterator it(res_method); + return VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method); + } +} + +bool MethodVerifier::CheckSignaturePolymorphicMethod(ArtMethod* method) { + mirror::Class* klass = method->GetDeclaringClass(); + if (klass != mirror::MethodHandle::StaticClass()) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "Signature polymorphic method must be declared in java.lang.invoke.MethodClass"; + return false; + } + + const char* method_name = method->GetName(); + if (strcmp(method_name, "invoke") != 0 && strcmp(method_name, "invokeExact") != 0) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "Signature polymorphic method name invalid: " << method_name; + return false; + } + + const DexFile::TypeList* types = method->GetParameterTypeList(); + if (types->Size() != 1) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "Signature polymorphic method has too many arguments " << types->Size() << " != 1"; + return false; + } + + const dex::TypeIndex argument_type_index = types->GetTypeItem(0).type_idx_; + const char* argument_descriptor = method->GetTypeDescriptorFromTypeIdx(argument_type_index); + if (strcmp(argument_descriptor, "[Ljava/lang/Object;") != 0) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "Signature polymorphic method has unexpected argument type: " << argument_descriptor; + return false; + } + + const char* return_descriptor = method->GetReturnTypeDescriptor(); + if (strcmp(return_descriptor, "Ljava/lang/Object;") != 0) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "Signature polymorphic method has unexpected return type: " << return_descriptor; + return false; + } + + return true; +} + +bool MethodVerifier::CheckSignaturePolymorphicReceiver(const Instruction* inst) { + const RegType& this_type = work_line_->GetInvocationThis(this, inst); + if (this_type.IsZero()) { + /* null pointer always passes (and always fails at run time) */ + return true; + } else if (!this_type.IsNonZeroReferenceTypes()) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "invoke-polymorphic receiver is not a reference: " + << this_type; + return false; + } else if (this_type.IsUninitializedReference()) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "invoke-polymorphic receiver is uninitialized: " + << this_type; + return false; + } else if (!this_type.HasClass()) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "invoke-polymorphic receiver has no class: " + << this_type; + return false; + } else if (!this_type.GetClass()->IsSubClass(mirror::MethodHandle::StaticClass())) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) + << "invoke-polymorphic receiver is not a subclass of MethodHandle: " + << this_type; + return false; + } + return true; } ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst, RegisterLine* reg_line, @@ -4146,7 +4264,7 @@ ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst, Regist } else { DCHECK_EQ(inst->Opcode(), Instruction::INVOKE_VIRTUAL_QUICK); } - const RegType& actual_arg_type = reg_line->GetInvocationThis(this, inst, is_range, allow_failure); + const RegType& actual_arg_type = reg_line->GetInvocationThis(this, inst, allow_failure); if (!actual_arg_type.HasClass()) { VLOG(verifier) << "Failed to get mirror::Class* from '" << actual_arg_type << "'"; return nullptr; @@ -4208,7 +4326,7 @@ ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst, // We use vAA as our expected arg count, rather than res_method->insSize, because we need to // match the call to the signature. Also, we might be calling through an abstract method // definition (which doesn't have register count values). - const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst, is_range); + const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst); if (actual_arg_type.IsConflict()) { // GetInvocationThis failed. return nullptr; } diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index f3faecd9a..fa5a69842 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -63,7 +63,8 @@ enum MethodType { METHOD_STATIC, // static METHOD_VIRTUAL, // virtual METHOD_SUPER, // super - METHOD_INTERFACE // interface + METHOD_INTERFACE, // interface + METHOD_POLYMORPHIC // polymorphic }; std::ostream& operator<<(std::ostream& os, const MethodType& rhs); @@ -474,6 +475,10 @@ class MethodVerifier { // reference isn't for an array class. bool CheckNewInstance(dex::TypeIndex idx); + // Perform static checks on a prototype indexing instruction. All we do here is ensure that the + // prototype index is in the valid range. + bool CheckPrototypeIndex(uint32_t idx); + /* Ensure that the string index is in the valid range. */ bool CheckStringIndex(uint32_t idx); @@ -512,6 +517,12 @@ class MethodVerifier { // - vA holds word count, vC holds index of first reg. bool CheckVarArgRangeRegs(uint32_t vA, uint32_t vC); + // Checks the method matches the expectations required to be signature polymorphic. + bool CheckSignaturePolymorphicMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); + + // Checks the invoked receiver matches the expectations for signature polymorphic methods. + bool CheckSignaturePolymorphicReceiver(const Instruction* inst) REQUIRES_SHARED(Locks::mutator_lock_); + // Extract the relative offset from a branch instruction. // Returns "false" on failure (e.g. this isn't a branch instruction). bool GetBranchOffset(uint32_t cur_offset, int32_t* pOffset, bool* pConditional, diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc index da3d94614..a6088aa03 100644 --- a/runtime/verifier/register_line.cc +++ b/runtime/verifier/register_line.cc @@ -44,8 +44,9 @@ bool RegisterLine::CheckConstructorReturn(MethodVerifier* verifier) const { } const RegType& RegisterLine::GetInvocationThis(MethodVerifier* verifier, const Instruction* inst, - bool is_range, bool allow_failure) { - const size_t args_count = is_range ? inst->VRegA_3rc() : inst->VRegA_35c(); + bool allow_failure) { + DCHECK(inst->IsInvoke()); + const size_t args_count = inst->VRegA(); if (args_count < 1) { if (!allow_failure) { verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'"; @@ -53,7 +54,7 @@ const RegType& RegisterLine::GetInvocationThis(MethodVerifier* verifier, const I return verifier->GetRegTypeCache()->Conflict(); } /* Get the element type of the array held in vsrc */ - const uint32_t this_reg = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); + const uint32_t this_reg = inst->VRegC(); const RegType& this_type = GetRegisterType(verifier, this_reg); if (!this_type.IsReferenceTypes()) { if (!allow_failure) { diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h index 7603a79c8..221aa80e4 100644 --- a/runtime/verifier/register_line.h +++ b/runtime/verifier/register_line.h @@ -217,7 +217,6 @@ class RegisterLine { */ const RegType& GetInvocationThis(MethodVerifier* verifier, const Instruction* inst, - bool is_range, bool allow_failure = false) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/test/954-invoke-polymorphic-verifier/build b/test/954-invoke-polymorphic-verifier/build new file mode 100755 index 000000000..a423ca6b4 --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/build @@ -0,0 +1,25 @@ +#!/bin/bash +# +# Copyright 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# make us exit on a failure +set -e + +if [[ $@ != *"--jvm"* ]]; then + # Don't do anything with jvm. + export USE_JACK=true +fi + +./default-build "$@" --experimental method-handles diff --git a/test/954-invoke-polymorphic-verifier/check b/test/954-invoke-polymorphic-verifier/check new file mode 100755 index 000000000..dc5ddb7fc --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/check @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Strip out temporary file path information and indicies from output. +sed -e "s/ [(]declaration of.*//" -e "s/\[0x[0-9A-F]*\] //g" "$2" > "$2.tmp" +diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null diff --git a/test/954-invoke-polymorphic-verifier/expected.txt b/test/954-invoke-polymorphic-verifier/expected.txt new file mode 100644 index 000000000..5df393aed --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/expected.txt @@ -0,0 +1,10 @@ +java.lang.VerifyError: Verifier rejected class MethodHandleNotInvoke: void MethodHandleNotInvoke.() failed to verify: void MethodHandleNotInvoke.(): void MethodHandleNotInvoke.(): couldn't find method java.lang.invoke.MethodHandle.notInvoke ([Ljava/lang/Object;)Ljava/lang/Object; +java.lang.VerifyError: Verifier rejected class MethodHandleToString: void MethodHandleToString.() failed to verify: void MethodHandleToString.(): void MethodHandleToString.(): invoke type (METHOD_POLYMORPHIC) does not match method type of java.lang.String java.lang.invoke.MethodHandle.toString() +java.lang.VerifyError: Verifier rejected class NonReference: void NonReference.() failed to verify: void NonReference.(): void NonReference.(): tried to get class from non-reference register v0 (type=Precise Low-half Constant: 0) +java.lang.VerifyError: Verifier rejected class TooFewArguments: void TooFewArguments.() failed to verify: void TooFewArguments.(): void TooFewArguments.(): Rejecting invocation, expected 2 argument registers, method signature has 3 or more +java.lang.VerifyError: Verifier rejected class TooManyArguments: void TooManyArguments.() failed to verify: void TooManyArguments.(): void TooManyArguments.(): Rejecting invocation, expected 4 argument registers, method signature has 3 +java.lang.VerifyError: Verifier rejected class BadThis: void BadThis.() failed to verify: void BadThis.(): void BadThis.(): 'this' argument 'Precise Reference: java.lang.String' not instance of 'Reference: java.lang.invoke.MethodHandle' +java.lang.VerifyError: Verifier rejected class FakeSignaturePolymorphic: void FakeSignaturePolymorphic.() failed to verify: void FakeSignaturePolymorphic.(): void FakeSignaturePolymorphic.(): invoke type (METHOD_POLYMORPHIC) does not match method type of java.lang.Object Main.invoke(java.lang.Object[]) +java.lang.VerifyError: Verifier rejected class BetterFakeSignaturePolymorphic: void BetterFakeSignaturePolymorphic.() failed to verify: void BetterFakeSignaturePolymorphic.(): Signature polymorphic method must be declared in java.lang.invoke.MethodClass +Passed Subclass test +java.lang.VerifyError: Verifier rejected class Unresolved: void Unresolved.() failed to verify: void Unresolved.(): invoke-polymorphic receiver has no class: Unresolved Reference: other.thing.Foo diff --git a/test/954-invoke-polymorphic-verifier/info.txt b/test/954-invoke-polymorphic-verifier/info.txt new file mode 100644 index 000000000..cb10d4257 --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/info.txt @@ -0,0 +1,3 @@ +Test cases that should be rejected by the method verifier. + +NOTE: needs to run under ART. diff --git a/test/954-invoke-polymorphic-verifier/run b/test/954-invoke-polymorphic-verifier/run new file mode 100755 index 000000000..a9f182288 --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/run @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# make us exit on a failure +set -e + +./default-run "$@" --experimental method-handles diff --git a/test/954-invoke-polymorphic-verifier/smali/BadThis.smali b/test/954-invoke-polymorphic-verifier/smali/BadThis.smali new file mode 100644 index 000000000..d9edf6713 --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/BadThis.smali @@ -0,0 +1,30 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.source "BadThis.smali" + +.class public LBadThis; +.super Ljava/lang/Object; + +.method public constructor ()V +.registers 4 + invoke-direct {p0}, Ljava/lang/Object;->()V + const-string v0, "0" + const-string v1, "1" + const-string v2, "2" + # v0 is a String, not a MethodHandle. + invoke-polymorphic {v0, v1, v2}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + return-void +.end method \ No newline at end of file diff --git a/test/954-invoke-polymorphic-verifier/smali/BetterFakeSignaturePolymorphic.smali b/test/954-invoke-polymorphic-verifier/smali/BetterFakeSignaturePolymorphic.smali new file mode 100644 index 000000000..631e704bd --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/BetterFakeSignaturePolymorphic.smali @@ -0,0 +1,43 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.source "BetterFakeSignaturePolymorphic.smali" + +.class public LBetterFakeSignaturePolymorphic; +.super Ljava/lang/Object; + +.method public constructor ()V +.registers 4 + invoke-direct {p0}, Ljava/lang/Object;->()V + invoke-static {}, LBetterFakeSignaturePolymorphic;->getMain()LMain; + move-result-object v0 + const/4 v1, 0 + move-object v1, v1 + # Fail here because Main;->invokeExact is on wrong class. + invoke-polymorphic {v0, v1}, LMain;->invokeExact([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object; + return-void +.end method + +.method public static getMethodHandle()Ljava/lang/invoke/MethodHandle; +.registers 1 + const/4 v0, 0 + return-object v0 +.end method + +.method public static getMain()LMain; +.registers 1 + const/4 v0, 0 + return-object v0 +.end method \ No newline at end of file diff --git a/test/954-invoke-polymorphic-verifier/smali/FakeSignaturePolymorphic.smali b/test/954-invoke-polymorphic-verifier/smali/FakeSignaturePolymorphic.smali new file mode 100644 index 000000000..5bd054a2d --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/FakeSignaturePolymorphic.smali @@ -0,0 +1,43 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.source "FakeSignaturePolymorphic.smali" + +.class public LFakeSignaturePolymorphic; +.super Ljava/lang/Object; + +.method public constructor ()V +.registers 4 + invoke-direct {p0}, Ljava/lang/Object;->()V + invoke-static {}, LFakeSignaturePolymorphic;->getMain()LMain; + move-result-object v0 + const/4 v1, 0 + move-object v1, v1 + # Fail here because Main;->invoke does not have right flags (ie not native or varargs). + invoke-polymorphic {v0, v1}, LMain;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object; + return-void +.end method + +.method public static getMethodHandle()Ljava/lang/invoke/MethodHandle; +.registers 1 + const/4 v0, 0 + return-object v0 +.end method + +.method public static getMain()LMain; +.registers 1 + const/4 v0, 0 + return-object v0 +.end method \ No newline at end of file diff --git a/test/954-invoke-polymorphic-verifier/smali/Main.smali b/test/954-invoke-polymorphic-verifier/smali/Main.smali new file mode 100644 index 000000000..5b5e5557d --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/Main.smali @@ -0,0 +1,85 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This is the test suite runner. It is written in smali rather than +# Java pending support in dx/dxmerge for invoke-polymorphic (b/33191712). + +.source "Main.smali" + +.class public LMain; +.super Ljava/lang/Object; + +.method public constructor()V +.registers 1 + invoke-direct {v0}, Ljava/lang/Object;->()V + return-void +.end method + +.method public static main([Ljava/lang/String;)V +.registers 1 + # New tests should be added here. + const-string v0, "MethodHandleNotInvoke" + invoke-static {v0}, LMain;->test(Ljava/lang/String;)V + const-string v0, "MethodHandleToString" + invoke-static {v0}, LMain;->test(Ljava/lang/String;)V + const-string v0, "NonReference" + invoke-static {v0}, LMain;->test(Ljava/lang/String;)V + const-string v0, "TooFewArguments" + invoke-static {v0}, LMain;->test(Ljava/lang/String;)V + const-string v0, "TooManyArguments" + invoke-static {v0}, LMain;->test(Ljava/lang/String;)V + const-string v0, "BadThis" + invoke-static {v0}, LMain;->test(Ljava/lang/String;)V + const-string v0, "FakeSignaturePolymorphic" + invoke-static {v0}, LMain;->test(Ljava/lang/String;)V + const-string v0, "BetterFakeSignaturePolymorphic" + invoke-static {v0}, LMain;->test(Ljava/lang/String;)V + const-string v0, "Subclass" + invoke-static {v0}, LMain;->test(Ljava/lang/String;)V + const-string v0, "Unresolved" + invoke-static {v0}, LMain;->test(Ljava/lang/String;)V + return-void +.end method + +.method public static test(Ljava/lang/String;)V +.registers 6 + :try_start_1 + invoke-static {v5}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class; + move-result-object v0 + invoke-virtual {v0}, Ljava/lang/Class;->newInstance()Ljava/lang/Object; + :try_end_1 + .catch Ljava/lang/VerifyError; {:try_start_1 .. :try_end_1} :catch_verifier + return-void + :catch_verifier + move-exception v3 + invoke-virtual {v3}, Ljava/lang/Exception;->toString()Ljava/lang/String; + move-result-object v3 + sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v2, v3}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V + return-void +.end method + +# A test method called "invoke", but on a class other than MethodHandle. +.method public invoke([Ljava/lang/Object;)Ljava/lang/Object; +.registers 2 + const/4 v0, 0 + aget-object v0, p0, v0 + return-object v0 +.end method + +# A test method called "invokeExact" that is native varargs, but is on a class +# other than MethodHandle. +.method public native varargs invokeExact([Ljava/lang/Object;)Ljava/lang/Object; +.end method \ No newline at end of file diff --git a/test/954-invoke-polymorphic-verifier/smali/MethodHandleNotInvoke.smali b/test/954-invoke-polymorphic-verifier/smali/MethodHandleNotInvoke.smali new file mode 100644 index 000000000..42546d179 --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/MethodHandleNotInvoke.smali @@ -0,0 +1,37 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.source "MethodHandleNotInvoke.smali" + +.class public LMethodHandleNotInvoke; +.super Ljava/lang/Object; + +.method public constructor ()V +.registers 4 + invoke-direct {p0}, Ljava/lang/Object;->()V + invoke-static {}, LMethodHandleNotInvoke;->getMethodHandle()Ljava/lang/invoke/MethodHandle; + move-result-object v0 + const/4 v1, 0 + move-object v1, v1 + # Attempt invoke-polymorphic on MethodHandle.notInvoke(). + invoke-polymorphic {v0, v1}, Ljava/lang/invoke/MethodHandle;->notInvoke([Ljava/lang/Object;)Ljava/lang/Object;, ([Ljava/lang/Object;)Ljava/lang/Object; + return-void +.end method + +.method public static getMethodHandle()Ljava/lang/invoke/MethodHandle; +.registers 1 + const/4 v0, 0 + return-object v0 +.end method diff --git a/test/954-invoke-polymorphic-verifier/smali/MethodHandleToString.smali b/test/954-invoke-polymorphic-verifier/smali/MethodHandleToString.smali new file mode 100644 index 000000000..c48429ca7 --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/MethodHandleToString.smali @@ -0,0 +1,35 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.source "MethodHandleToString.smali" + +.class public LMethodHandleToString; +.super Ljava/lang/Object; + +.method public constructor ()V +.registers 1 + invoke-direct {p0}, Ljava/lang/Object;->()V + invoke-static {}, LMethodHandleToString;->getMethodHandle()Ljava/lang/invoke/MethodHandle; + move-result-object v0 + # Attempt invoke-polymorphic on MethodHandle.toString(). + invoke-polymorphic {v0}, Ljava/lang/invoke/MethodHandle;->toString()Ljava/lang/String;, ()Ljava/lang/Object; + return-void +.end method + +.method public static getMethodHandle()Ljava/lang/invoke/MethodHandle; +.registers 1 + const/4 v0, 0 + return-object v0 +.end method diff --git a/test/954-invoke-polymorphic-verifier/smali/NonReference.smali b/test/954-invoke-polymorphic-verifier/smali/NonReference.smali new file mode 100644 index 000000000..4e1eff235 --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/NonReference.smali @@ -0,0 +1,30 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.source "NonReference.smali" + +.class public LNonReference; +.super Ljava/lang/Object; + +.method public constructor ()V +.registers 4 + invoke-direct {p0}, Ljava/lang/Object;->()V + # Set v0 to have incorrect type (not a MethodHandle) and value (not null). + const-wide v0, 0 + const-string v1, "1" + const-string v2, "2" + invoke-polymorphic {v0, v1, v2}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + return-void +.end method diff --git a/test/954-invoke-polymorphic-verifier/smali/Subclass.smali b/test/954-invoke-polymorphic-verifier/smali/Subclass.smali new file mode 100644 index 000000000..7ef61bedc --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/Subclass.smali @@ -0,0 +1,45 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.source "Subclass.smali" + +.class public LSubclass; +.super Ljava/lang/Object; + +.method public constructor ()V +.registers 3 + invoke-direct {p0}, Ljava/lang/Object;->()V + goto :happy + # Get a MethodHandleImpl instance (subclass of MethodHandle). + invoke-static {}, LSubclass;->getMethodHandleSubclassInstance()Ljava/lang/invoke/MethodHandleImpl; + move-result-object v0 + const-string v1, "1" + const-string v2, "2" + # Calling MethodHandle.invoke() on MethodHandleImpl instance (subclass of MethodHandle) => Okay + invoke-polymorphic {v0, v1, v2}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + # Calling MethodHandleImpl.invoke() rather than MethodHandle.invoke() [ declaring class is okay ] => Okay + invoke-polymorphic {v0, v1, v2}, Ljava/lang/invoke/MethodHandleImpl;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; +:happy + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + const-string v2, "Passed Subclass test" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V + return-void +.end method + +.method public static getMethodHandleSubclassInstance()Ljava/lang/invoke/MethodHandleImpl; +.registers 1 + const/4 v0, 0 + return-object v0 +.end method diff --git a/test/954-invoke-polymorphic-verifier/smali/TooFewArguments.smali b/test/954-invoke-polymorphic-verifier/smali/TooFewArguments.smali new file mode 100644 index 000000000..da29c6f13 --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/TooFewArguments.smali @@ -0,0 +1,33 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.source "TooFewArguments.smali" + +.class public LTooFewArguments; +.super Ljava/lang/Object; + +.method public constructor ()V +.registers 4 + invoke-direct {p0}, Ljava/lang/Object;->()V + # Set up v0 as a null MethodHandle + const/4 v0, 0 + move-object v0, v0 + invoke-virtual {v0}, Ljava/lang/invoke/MethodHandle;->asFixedArity()Ljava/lang/invoke/MethodHandle; + move-result-object v0 + const-string v1, "1" + # Invoke with one argument too few for prototype. + invoke-polymorphic {v0, v1}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + return-void +.end method diff --git a/test/954-invoke-polymorphic-verifier/smali/TooManyArguments.smali b/test/954-invoke-polymorphic-verifier/smali/TooManyArguments.smali new file mode 100644 index 000000000..bc0135e0d --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/TooManyArguments.smali @@ -0,0 +1,35 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.source "TooManyArguments.smali" + +.class public LTooManyArguments; +.super Ljava/lang/Object; + +.method public constructor ()V +.registers 4 + invoke-direct {p0}, Ljava/lang/Object;->()V + # Set up v0 as a null MethodHandle + const/4 v0, 0 + move-object v0, v0 + invoke-virtual {v0}, Ljava/lang/invoke/MethodHandle;->asFixedArity()Ljava/lang/invoke/MethodHandle; + move-result-object v0 + const-string v1, "1" + const-string v2, "2" + const-string v3, "3" + # Invoke with one argument too many for prototype. + invoke-polymorphic {v0, v1, v2, v3}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + return-void +.end method diff --git a/test/954-invoke-polymorphic-verifier/smali/Unresolved.smali b/test/954-invoke-polymorphic-verifier/smali/Unresolved.smali new file mode 100644 index 000000000..882f0e925 --- /dev/null +++ b/test/954-invoke-polymorphic-verifier/smali/Unresolved.smali @@ -0,0 +1,40 @@ +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.source "Unresolved.smali" + +.class public LUnresolved; +.super Ljava/lang/Object; + +.method public constructor ()V +.registers 3 +.line 23 + invoke-direct {p0}, Ljava/lang/Object;->()V + # Get an unresolvable instance (abstract class) + invoke-static {}, LAbstract;->getUnresolvedInstance()Lother/thing/Foo; + move-result-object v0 + const-string v1, "1" + const-string v2, "2" + # Calling MethodHandle.invoke() on unresolved receiver. + invoke-polymorphic {v0, v1, v2}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + return-void +.end method + +.method public static getUnresolvedInstance()Lother/thing/Foo; +.registers 1 +.line 37 + const/4 v0, 0 + return-object v0 +.end method -- 2.11.0