diff options
-rw-r--r-- | openjdkjvmti/ti_redefine.cc | 35 | ||||
-rw-r--r-- | openjdkjvmti/ti_redefine.h | 8 | ||||
-rw-r--r-- | runtime/art_method.h | 6 | ||||
-rw-r--r-- | runtime/mirror/class.cc | 9 | ||||
-rw-r--r-- | runtime/mirror/class.h | 3 | ||||
-rw-r--r-- | runtime/verifier/class_verifier.cc | 70 | ||||
-rw-r--r-- | runtime/verifier/class_verifier.h | 30 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 8 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.h | 2 | ||||
-rw-r--r-- | test/1989-transform-bad-monitor/expected.txt | 6 | ||||
-rw-r--r-- | test/1989-transform-bad-monitor/info.txt | 6 | ||||
-rwxr-xr-x | test/1989-transform-bad-monitor/run | 17 | ||||
-rw-r--r-- | test/1989-transform-bad-monitor/src/Main.java | 21 | ||||
l--------- | test/1989-transform-bad-monitor/src/art/Redefinition.java | 1 | ||||
-rw-r--r-- | test/1989-transform-bad-monitor/src/art/Test1989.java | 97 |
15 files changed, 317 insertions, 2 deletions
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index 67d10b6afc..df25261654 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -1496,7 +1496,14 @@ bool Redefiner::ClassRedefinition::CheckVerification(const RedefinitionDataIter& &error); switch (failure) { case art::verifier::FailureKind::kNoFailure: + // TODO It is possible that by doing redefinition previous NO_COMPILE verification failures + // were fixed. It would be nice to reflect this in the new implementations. + return true; case art::verifier::FailureKind::kSoftFailure: + // Soft failures might require interpreter on some methods. It won't prevent redefinition but + // it does mean we need to run the verifier again and potentially update method flags after + // performing the swap. + needs_reverify_ = true; return true; case art::verifier::FailureKind::kHardFailure: { RecordFailure(ERR(FAILS_VERIFICATION), "Failed to verify class. Error was: " + error); @@ -1881,9 +1888,37 @@ jvmtiError Redefiner::Run() { // TODO Do the dex_file release at a more reasonable place. This works but it muddles who really // owns the DexFile and when ownership is transferred. ReleaseAllDexFiles(); + // By now the class-linker knows about all the classes so we can safetly retry verification and + // update method flags. + ReverifyClasses(holder); return OK; } +void Redefiner::ReverifyClasses(RedefinitionDataHolder& holder) { + art::ScopedAssertNoThreadSuspension nts("Updating method flags"); + for (RedefinitionDataIter data = holder.begin(); data != holder.end(); ++data) { + data.GetRedefinition().ReverifyClass(data); + } +} + +void Redefiner::ClassRedefinition::ReverifyClass(const RedefinitionDataIter &cur_data) { + if (!needs_reverify_) { + return; + } + VLOG(plugin) << "Reverifying " << class_sig_ << " due to soft failures"; + std::string error; + // TODO Make verification log level lower + art::verifier::FailureKind failure = + art::verifier::ClassVerifier::ReverifyClass(driver_->self_, + cur_data.GetMirrorClass(), + /*log_level=*/ + art::verifier::HardFailLogMode::kLogWarning, + /*api_level=*/ + art::Runtime::Current()->GetTargetSdkVersion(), + &error); + CHECK_NE(failure, art::verifier::FailureKind::kHardFailure); +} + void Redefiner::ClassRedefinition::UpdateMethods(art::ObjPtr<art::mirror::Class> mclass, const art::dex::ClassDef& class_def) { art::ClassLinker* linker = driver_->runtime_->GetClassLinker(); diff --git a/openjdkjvmti/ti_redefine.h b/openjdkjvmti/ti_redefine.h index d10758c058..dad085de59 100644 --- a/openjdkjvmti/ti_redefine.h +++ b/openjdkjvmti/ti_redefine.h @@ -209,6 +209,9 @@ class Redefiner { void UpdateClass(const RedefinitionDataIter& cur_data) REQUIRES(art::Locks::mutator_lock_); + void ReverifyClass(const RedefinitionDataIter& cur_data) + REQUIRES(art::Locks::mutator_lock_); + void CollectNewFieldAndMethodMappings(const RedefinitionDataIter& data, std::map<art::ArtMethod*, art::ArtMethod*>* method_map, std::map<art::ArtField*, art::ArtField*>* field_map) @@ -248,6 +251,10 @@ class Redefiner { bool added_fields_ = false; bool added_methods_ = false; + + // Does the class need to be reverified due to verification soft-fails possibly forcing + // interpreter or lock-counting? + bool needs_reverify_ = false; }; ArtJvmTiEnv* env_; @@ -294,6 +301,7 @@ class Redefiner { bool FinishAllRemainingAllocations(RedefinitionDataHolder& holder) REQUIRES_SHARED(art::Locks::mutator_lock_); void ReleaseAllDexFiles() REQUIRES_SHARED(art::Locks::mutator_lock_); + void ReverifyClasses(RedefinitionDataHolder& holder) REQUIRES(art::Locks::mutator_lock_); void UnregisterAllBreakpoints() REQUIRES_SHARED(art::Locks::mutator_lock_); // Restores the old obsolete methods maps if it turns out they weren't needed (ie there were no // new obsolete methods). diff --git a/runtime/art_method.h b/runtime/art_method.h index d84ea7c4bc..d4fb5d7b90 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -335,6 +335,11 @@ class ArtMethod final { DCHECK(!IsNative()); AddAccessFlags(kAccSkipAccessChecks); } + void ClearSkipAccessChecks() { + // SkipAccessChecks() is applicable only to non-native methods. + DCHECK(!IsNative()); + ClearAccessFlags(kAccSkipAccessChecks); + } bool PreviouslyWarm() { if (IsIntrinsic()) { @@ -363,6 +368,7 @@ class ArtMethod final { void SetMustCountLocks() { AddAccessFlags(kAccMustCountLocks); + ClearAccessFlags(kAccSkipAccessChecks); } // Returns true if this method could be overridden by a default method. diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 455f98d489..a0e8a237c5 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -1031,6 +1031,15 @@ ArtField* Class::FindField(Thread* self, return nullptr; } +void Class::ClearSkipAccessChecksFlagOnAllMethods(PointerSize pointer_size) { + DCHECK(IsVerified()); + for (auto& m : GetMethods(pointer_size)) { + if (!m.IsNative() && m.IsInvokable()) { + m.ClearSkipAccessChecks(); + } + } +} + void Class::SetSkipAccessChecksFlagOnAllMethods(PointerSize pointer_size) { DCHECK(IsVerified()); for (auto& m : GetMethods(pointer_size)) { diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 6ed20ed02f..d925a96d9c 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -1134,6 +1134,9 @@ class MANAGED Class final : public Object { static ObjPtr<mirror::Class> GetPrimitiveClass(ObjPtr<mirror::String> name) REQUIRES_SHARED(Locks::mutator_lock_); + // Clear the kAccSkipAccessChecks flag on each method, for class redefinition. + void ClearSkipAccessChecksFlagOnAllMethods(PointerSize pointer_size) + REQUIRES_SHARED(Locks::mutator_lock_); // When class is verified, set the kAccSkipAccessChecks flag on each method. void SetSkipAccessChecksFlagOnAllMethods(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc index 1df11ada50..66f5801634 100644 --- a/runtime/verifier/class_verifier.cc +++ b/runtime/verifier/class_verifier.cc @@ -20,6 +20,7 @@ #include <android-base/stringprintf.h> #include "art_method-inl.h" +#include "base/enums.h" #include "base/systrace.h" #include "base/utils.h" #include "class_linker.h" @@ -28,11 +29,13 @@ #include "dex/class_reference.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" +#include "handle.h" #include "handle_scope-inl.h" #include "method_verifier-inl.h" #include "mirror/class-inl.h" #include "mirror/dex_cache.h" #include "runtime.h" +#include "thread.h" namespace art { namespace verifier { @@ -43,6 +46,30 @@ using android::base::StringPrintf; // sure we only print this once. static bool gPrintedDxMonitorText = false; +FailureKind ClassVerifier::ReverifyClass(Thread* self, + ObjPtr<mirror::Class> klass, + HardFailLogMode log_level, + uint32_t api_level, + std::string* error) { + DCHECK(!Runtime::Current()->IsAotCompiler()); + StackHandleScope<1> hs(self); + Handle<mirror::Class> h_klass(hs.NewHandle(klass)); + ScopedAssertNoThreadSuspension sants(__FUNCTION__); + FailureKind res = CommonVerifyClass(self, + h_klass.Get(), + /*callbacks=*/nullptr, + /*allow_soft_failures=*/false, + log_level, + api_level, + /*can_allocate=*/ false, + error); + if (res == FailureKind::kSoftFailure) { + // We cannot skip access checks since there was a soft failure. + h_klass->ClearSkipAccessChecksFlagOnAllMethods(kRuntimePointerSize); + } + return res; +} + FailureKind ClassVerifier::VerifyClass(Thread* self, ObjPtr<mirror::Class> klass, CompilerCallbacks* callbacks, @@ -53,6 +80,23 @@ FailureKind ClassVerifier::VerifyClass(Thread* self, if (klass->IsVerified()) { return FailureKind::kNoFailure; } + return CommonVerifyClass(self, + klass, + callbacks, + allow_soft_failures, + log_level, + api_level, + /*can_allocate=*/ true, + error); +} +FailureKind ClassVerifier::CommonVerifyClass(Thread* self, + ObjPtr<mirror::Class> klass, + CompilerCallbacks* callbacks, + bool allow_soft_failures, + HardFailLogMode log_level, + uint32_t api_level, + bool can_allocate, + std::string* error) { bool early_failure = false; std::string failure_message; const DexFile& dex_file = klass->GetDexFile(); @@ -89,6 +133,30 @@ FailureKind ClassVerifier::VerifyClass(Thread* self, allow_soft_failures, log_level, api_level, + can_allocate, + error); +} + +FailureKind ClassVerifier::VerifyClass(Thread* self, + const DexFile* dex_file, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + const dex::ClassDef& class_def, + CompilerCallbacks* callbacks, + bool allow_soft_failures, + HardFailLogMode log_level, + uint32_t api_level, + std::string* error) { + return VerifyClass(self, + dex_file, + dex_cache, + class_loader, + class_def, + callbacks, + allow_soft_failures, + log_level, + api_level, + /*can_allocate=*/!Runtime::Current()->IsAotCompiler(), error); } @@ -101,6 +169,7 @@ FailureKind ClassVerifier::VerifyClass(Thread* self, bool allow_soft_failures, HardFailLogMode log_level, uint32_t api_level, + bool can_allocate, std::string* error) { // A class must not be abstract and final. if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) { @@ -156,6 +225,7 @@ FailureKind ClassVerifier::VerifyClass(Thread* self, /*need_precise_constants=*/ false, api_level, Runtime::Current()->IsAotCompiler(), + can_allocate, &hard_failure_msg); if (result.kind == FailureKind::kHardFailure) { if (failure_data.kind == FailureKind::kHardFailure) { diff --git a/runtime/verifier/class_verifier.h b/runtime/verifier/class_verifier.h index db5e4f592d..c97ea24799 100644 --- a/runtime/verifier/class_verifier.h +++ b/runtime/verifier/class_verifier.h @@ -50,6 +50,14 @@ namespace verifier { // Verifier that ensures the complete class is OK. class ClassVerifier { public: + // Redo verification on a loaded class. This is for use by class redefinition. Since the class is + // already loaded and in use this can only be performed with the mutator lock held. + static FailureKind ReverifyClass(Thread* self, + ObjPtr<mirror::Class> klass, + HardFailLogMode log_level, + uint32_t api_level, + std::string* error) + REQUIRES(Locks::mutator_lock_); // Verify a class. Returns "kNoFailure" on success. static FailureKind VerifyClass(Thread* self, ObjPtr<mirror::Class> klass, @@ -70,6 +78,18 @@ class ClassVerifier { uint32_t api_level, std::string* error) REQUIRES_SHARED(Locks::mutator_lock_); + static FailureKind VerifyClass(Thread* self, + const DexFile* dex_file, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + const dex::ClassDef& class_def, + CompilerCallbacks* callbacks, + bool allow_soft_failures, + HardFailLogMode log_level, + uint32_t api_level, + bool can_allocate, + std::string* error) + REQUIRES_SHARED(Locks::mutator_lock_); static void Init(ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_); static void Shutdown(); @@ -78,6 +98,16 @@ class ClassVerifier { REQUIRES_SHARED(Locks::mutator_lock_); private: + static FailureKind CommonVerifyClass(Thread* self, + ObjPtr<mirror::Class> klass, + CompilerCallbacks* callbacks, + bool allow_soft_failures, + HardFailLogMode log_level, + uint32_t api_level, + bool can_allocate, + std::string* error) + REQUIRES_SHARED(Locks::mutator_lock_); + DISALLOW_COPY_AND_ASSIGN(ClassVerifier); }; diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 839491ec3e..29bc40c30c 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -5112,6 +5112,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, bool need_precise_constants, uint32_t api_level, bool aot_mode, + bool allow_suspension, std::string* hard_failure_msg) { if (VLOG_IS_ON(verifier_debug)) { return VerifyMethod<true>(self, @@ -5131,6 +5132,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, need_precise_constants, api_level, aot_mode, + allow_suspension, hard_failure_msg); } else { return VerifyMethod<false>(self, @@ -5150,6 +5152,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, need_precise_constants, api_level, aot_mode, + allow_suspension, hard_failure_msg); } } @@ -5172,6 +5175,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, bool need_precise_constants, uint32_t api_level, bool aot_mode, + bool allow_suspension, std::string* hard_failure_msg) { MethodVerifier::FailureData result; uint64_t start_ns = kTimeVerifyMethod ? NanoTime() : 0; @@ -5182,8 +5186,8 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, dex_file, code_item, method_idx, - /* can_load_classes= */ true, - /* allow_thread_suspension= */ true, + /* can_load_classes= */ allow_suspension, + /* allow_thread_suspension= */ allow_suspension, allow_soft_failures, aot_mode, dex_cache, diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index aab6ee55c1..09d384a069 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -253,6 +253,7 @@ class MethodVerifier { bool need_precise_constants, uint32_t api_level, bool aot_mode, + bool allow_suspension, std::string* hard_failure_msg) REQUIRES_SHARED(Locks::mutator_lock_); @@ -274,6 +275,7 @@ class MethodVerifier { bool need_precise_constants, uint32_t api_level, bool aot_mode, + bool allow_suspension, std::string* hard_failure_msg) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/test/1989-transform-bad-monitor/expected.txt b/test/1989-transform-bad-monitor/expected.txt new file mode 100644 index 0000000000..65ec72d5ef --- /dev/null +++ b/test/1989-transform-bad-monitor/expected.txt @@ -0,0 +1,6 @@ +hello without locks +Goodbye before unlock +Goodbye after unlock +Got exception of type class java.lang.IllegalMonitorStateException +Make sure locks aren't held +Locks are good. diff --git a/test/1989-transform-bad-monitor/info.txt b/test/1989-transform-bad-monitor/info.txt new file mode 100644 index 0000000000..0056464cd0 --- /dev/null +++ b/test/1989-transform-bad-monitor/info.txt @@ -0,0 +1,6 @@ +Tests basic functions in the jvmti plugin. + +b/142876078 + +This tests that redefining a method to have unbalanced locks doesn't cause issues and the method +is given lock-counting and not compiled. diff --git a/test/1989-transform-bad-monitor/run b/test/1989-transform-bad-monitor/run new file mode 100755 index 0000000000..c6e62ae6cd --- /dev/null +++ b/test/1989-transform-bad-monitor/run @@ -0,0 +1,17 @@ +#!/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. + +./default-run "$@" --jvmti diff --git a/test/1989-transform-bad-monitor/src/Main.java b/test/1989-transform-bad-monitor/src/Main.java new file mode 100644 index 0000000000..9c61e894a4 --- /dev/null +++ b/test/1989-transform-bad-monitor/src/Main.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2017 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. + */ + +public class Main { + public static void main(String[] args) throws Exception { + art.Test1989.run(); + } +} diff --git a/test/1989-transform-bad-monitor/src/art/Redefinition.java b/test/1989-transform-bad-monitor/src/art/Redefinition.java new file mode 120000 index 0000000000..81eaf31bbb --- /dev/null +++ b/test/1989-transform-bad-monitor/src/art/Redefinition.java @@ -0,0 +1 @@ +../../../jvmti-common/Redefinition.java
\ No newline at end of file diff --git a/test/1989-transform-bad-monitor/src/art/Test1989.java b/test/1989-transform-bad-monitor/src/art/Test1989.java new file mode 100644 index 0000000000..fb16c22483 --- /dev/null +++ b/test/1989-transform-bad-monitor/src/art/Test1989.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package art; + +import java.util.Base64; +public class Test1989 { + + static class Transform { + public void sayHi(Object l_first, Object l_second) { + System.out.println("hello without locks"); + } + } + + /** + * base64 encoded class/dex file for + * class Transform { + * public void sayHi(Object l_first, Object l_second) { + * monitor-enter l_first + * monitor-enter l_second + * System.out.println("Goodbye before unlock"); + * monitor-exit l_second + * System.out.println("Goodbye after unlock"); + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( +"yv66vgADAC0AHgEAFEdvb2RieWUgYWZ0ZXIgdW5sb2NrDAAYAB0BABBqYXZhL2xhbmcvT2JqZWN0" + +"AQAGPGluaXQ+BwADDAAEAAkHABEBABZhcnQvVGVzdDE5ODkkVHJhbnNmb3JtAQADKClWBwAVAQAE" + +"Q29kZQgAHAkACgACAQANVGVzdDE5ODkuamF2YQEAClNvdXJjZUZpbGUMABIAGwEAE2phdmEvaW8v" + +"UHJpbnRTdHJlYW0BAAdwcmludGxuCgAFAAYBAAVzYXlIaQEAEGphdmEvbGFuZy9TeXN0ZW0IAAEK" + +"AAcAEAEAA291dAcACAEAJyhMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL09iamVjdDspVgEA" + +"FShMamF2YS9sYW5nL1N0cmluZzspVgEAFUdvb2RieWUgYmVmb3JlIHVubG9jawEAFUxqYXZhL2lv" + +"L1ByaW50U3RyZWFtOwAgABkABQAAAAAAAgAAAAQACQABAAsAAAARAAEAAQAAAAUqtwATsQAAAAAA" + +"AQAUABoAAQALAAAAIwACAAMAAAAXK8IswrIADRIMtgAXLMOyAA0SFrYAF7EAAAAAAAEADwAAAAIA" + +"Dg=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( +"ZGV4CjAzNQB5oAZwVUwJoMSgbr1BNffRcXjpPMVhYzgYBAAAcAAAAHhWNBIAAAAAAAAAAFQDAAAW" + +"AAAAcAAAAAkAAADIAAAAAwAAAOwAAAABAAAAEAEAAAQAAAAYAQAAAQAAADgBAADAAgAAWAEAAFgB" + +"AABgAQAAdgEAAI0BAACnAQAAtwEAANsBAAD7AQAAEgIAACYCAAA6AgAATgIAAF0CAABoAgAAawIA" + +"AG8CAAB0AgAAgQIAAIcCAACMAgAAlQIAAJwCAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAA" + +"CgAAAA0AAAANAAAACAAAAAAAAAAPAAAACAAAAKQCAAAOAAAACAAAAKwCAAAHAAQAEgAAAAAAAAAA" + +"AAAAAAABABQAAAAEAAIAEwAAAAUAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAsAAADYAgAARAMAAAAA" + +"AAAGPGluaXQ+ABRHb29kYnllIGFmdGVyIHVubG9jawAVR29vZGJ5ZSBiZWZvcmUgdW5sb2NrABhM" + +"YXJ0L1Rlc3QxOTg5JFRyYW5zZm9ybTsADkxhcnQvVGVzdDE5ODk7ACJMZGFsdmlrL2Fubm90YXRp" + +"b24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24vSW5uZXJDbGFzczsAFUxqYXZh" + +"L2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsA" + +"EkxqYXZhL2xhbmcvU3lzdGVtOwANVGVzdDE5ODkuamF2YQAJVHJhbnNmb3JtAAFWAAJWTAADVkxM" + +"AAthY2Nlc3NGbGFncwAEbmFtZQADb3V0AAdwcmludGxuAAVzYXlIaQAFdmFsdWUAAAIAAAAFAAUA" + +"AQAAAAYAAgMCEAQIERcMAgIBFRgBAAAAAAAAAAAAAAACAAAAuwIAALICAADMAgAAAAAAAAAAAAAA" + +"AAAABgAOAAgCAAAOHh54H3gAAAEAAQABAAAA6AIAAAQAAABwEAMAAAAOAAUAAwACAAAA7AIAABIA" + +"AAAdAx0EYgAAABoBAgBuIAIAEAAeBGIDAAAaBAEAbiACAEMADgAAAAEBAICABPgFAQGQBgAAEAAA" + +"AAAAAAABAAAAAAAAAAEAAAAWAAAAcAAAAAIAAAAJAAAAyAAAAAMAAAADAAAA7AAAAAQAAAABAAAA" + +"EAEAAAUAAAAEAAAAGAEAAAYAAAABAAAAOAEAAAIgAAAWAAAAWAEAAAEQAAACAAAApAIAAAQgAAAC" + +"AAAAsgIAAAMQAAADAAAAxAIAAAYgAAABAAAA2AIAAAMgAAACAAAA6AIAAAEgAAACAAAA+AIAAAAg" + +"AAABAAAARAMAAAAQAAABAAAAVAMAAA=="); + + public static void run() throws Exception { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(new Transform()); + } + + public static void doTest(Transform t) throws Exception { + Object a = new Object(); + Object b = new Object(); + t.sayHi(a, b); + Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + try { + t.sayHi(a, b); + } catch (Throwable e) { + System.out.println("Got exception of type " + e.getClass()); + } + System.out.println("Make sure locks aren't held"); + Thread thr = new Thread(() -> { + synchronized(a) { + synchronized (b) { + System.out.println("Locks are good."); + } + } + }); + thr.start(); + thr.join(); + } +} |