diff options
| author | 2017-01-25 10:30:20 -0800 | |
|---|---|---|
| committer | 2017-02-06 13:26:12 -0800 | |
| commit | 6161f132ca464ebcac43a5bece2f4e758dee1da3 (patch) | |
| tree | d33175be2a08a4f198a8bb0ea556edebd24de6d7 | |
| parent | 406402baa4900c36b3fe27b03bf9e04e978e50be (diff) | |
Add support for checking method and field invariants for redefinition.
Test: mma -j40 test-art-host
Change-Id: I62c5d967522c2b3f455253a299c889fd5be19232
| -rw-r--r-- | runtime/openjdkjvmti/ti_redefine.cc | 139 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_redefine.h | 14 | ||||
| -rw-r--r-- | test/921-hello-failure/expected.txt | 18 | ||||
| -rw-r--r-- | test/921-hello-failure/src/FieldChange.java | 61 | ||||
| -rw-r--r-- | test/921-hello-failure/src/Main.java | 6 | ||||
| -rw-r--r-- | test/921-hello-failure/src/MethodChange.java | 57 | ||||
| -rw-r--r-- | test/921-hello-failure/src/MissingField.java | 58 | ||||
| -rw-r--r-- | test/921-hello-failure/src/MissingMethod.java | 57 | ||||
| -rw-r--r-- | test/921-hello-failure/src/NewField.java | 60 | ||||
| -rw-r--r-- | test/921-hello-failure/src/NewMethod.java | 60 | ||||
| -rw-r--r-- | test/921-hello-failure/src/Transform3.java | 24 | ||||
| -rw-r--r-- | test/921-hello-failure/src/Transform4.java | 25 | ||||
| -rw-r--r-- | test/942-private-recursive/src/Transform.java | 8 |
13 files changed, 572 insertions, 15 deletions
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc index 4b8108accf..d1fbd758bd 100644 --- a/runtime/openjdkjvmti/ti_redefine.cc +++ b/runtime/openjdkjvmti/ti_redefine.cc @@ -48,7 +48,7 @@ #include "jit/jit_code_cache.h" #include "jni_env_ext-inl.h" #include "jvmti_allocator.h" -#include "mirror/class.h" +#include "mirror/class-inl.h" #include "mirror/class_ext.h" #include "mirror/object.h" #include "object_lock.h" @@ -490,6 +490,143 @@ void Redefiner::ClassRedefinition::FillObsoleteMethodMap( } } +// Try and get the declared method. First try to get a virtual method then a direct method if that's +// not found. +static art::ArtMethod* FindMethod(art::Handle<art::mirror::Class> klass, + const char* name, + art::Signature sig) REQUIRES_SHARED(art::Locks::mutator_lock_) { + art::ArtMethod* m = klass->FindDeclaredVirtualMethod(name, sig, art::kRuntimePointerSize); + if (m == nullptr) { + m = klass->FindDeclaredDirectMethod(name, sig, art::kRuntimePointerSize); + } + return m; +} + +bool Redefiner::ClassRedefinition::CheckSameMethods() { + art::StackHandleScope<1> hs(driver_->self_); + art::Handle<art::mirror::Class> h_klass(hs.NewHandle(GetMirrorClass())); + DCHECK_EQ(dex_file_->NumClassDefs(), 1u); + + art::ClassDataItemIterator new_iter(*dex_file_, + dex_file_->GetClassData(dex_file_->GetClassDef(0))); + + // Make sure we have the same number of methods. + uint32_t num_new_method = new_iter.NumVirtualMethods() + new_iter.NumDirectMethods(); + uint32_t num_old_method = h_klass->GetDeclaredMethodsSlice(art::kRuntimePointerSize).size(); + if (num_new_method != num_old_method) { + bool bigger = num_new_method > num_old_method; + RecordFailure(bigger ? ERR(UNSUPPORTED_REDEFINITION_METHOD_ADDED) + : ERR(UNSUPPORTED_REDEFINITION_METHOD_DELETED), + StringPrintf("Total number of declared methods changed from %d to %d", + num_old_method, num_new_method)); + return false; + } + + // Skip all of the fields. We should have already checked this. + while (new_iter.HasNextStaticField() || new_iter.HasNextInstanceField()) { + new_iter.Next(); + } + // Check each of the methods. NB we don't need to specifically check for removals since the 2 dex + // files have the same number of methods, which means there must be an equal amount of additions + // and removals. + for (; new_iter.HasNextVirtualMethod() || new_iter.HasNextDirectMethod(); new_iter.Next()) { + // Get the data on the method we are searching for + const art::DexFile::MethodId& new_method_id = dex_file_->GetMethodId(new_iter.GetMemberIndex()); + const char* new_method_name = dex_file_->GetMethodName(new_method_id); + art::Signature new_method_signature = dex_file_->GetMethodSignature(new_method_id); + art::ArtMethod* old_method = FindMethod(h_klass, new_method_name, new_method_signature); + // If we got past the check for the same number of methods above that means there must be at + // least one added and one removed method. We will return the ADDED failure message since it is + // easier to get a useful error report for it. + if (old_method == nullptr) { + RecordFailure(ERR(UNSUPPORTED_REDEFINITION_METHOD_ADDED), + StringPrintf("Unknown method '%s' (sig: %s) was added!", + new_method_name, + new_method_signature.ToString().c_str())); + return false; + } + // Since direct methods have different flags than virtual ones (specifically direct methods must + // have kAccPrivate or kAccStatic or kAccConstructor flags) we can tell if a method changes from + // virtual to direct. + uint32_t new_flags = new_iter.GetMethodAccessFlags(); + if (new_flags != (old_method->GetAccessFlags() & art::kAccValidMethodFlags)) { + RecordFailure(ERR(UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED), + StringPrintf("method '%s' (sig: %s) had different access flags", + new_method_name, + new_method_signature.ToString().c_str())); + return false; + } + } + return true; +} + +bool Redefiner::ClassRedefinition::CheckSameFields() { + art::StackHandleScope<1> hs(driver_->self_); + art::Handle<art::mirror::Class> h_klass(hs.NewHandle(GetMirrorClass())); + DCHECK_EQ(dex_file_->NumClassDefs(), 1u); + art::ClassDataItemIterator new_iter(*dex_file_, + dex_file_->GetClassData(dex_file_->GetClassDef(0))); + const art::DexFile& old_dex_file = h_klass->GetDexFile(); + art::ClassDataItemIterator old_iter(old_dex_file, + old_dex_file.GetClassData(*h_klass->GetClassDef())); + // Instance and static fields can be differentiated by their flags so no need to check them + // separately. + while (new_iter.HasNextInstanceField() || new_iter.HasNextStaticField()) { + // Get the data on the method we are searching for + const art::DexFile::FieldId& new_field_id = dex_file_->GetFieldId(new_iter.GetMemberIndex()); + const char* new_field_name = dex_file_->GetFieldName(new_field_id); + const char* new_field_type = dex_file_->GetFieldTypeDescriptor(new_field_id); + + if (!(old_iter.HasNextInstanceField() || old_iter.HasNextStaticField())) { + // We are missing the old version of this method! + RecordFailure(ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED), + StringPrintf("Unknown field '%s' (type: %s) added!", + new_field_name, + new_field_type)); + return false; + } + + const art::DexFile::FieldId& old_field_id = old_dex_file.GetFieldId(old_iter.GetMemberIndex()); + const char* old_field_name = old_dex_file.GetFieldName(old_field_id); + const char* old_field_type = old_dex_file.GetFieldTypeDescriptor(old_field_id); + + // Check name and type. + if (strcmp(old_field_name, new_field_name) != 0 || + strcmp(old_field_type, new_field_type) != 0) { + RecordFailure(ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED), + StringPrintf("Field changed from '%s' (sig: %s) to '%s' (sig: %s)!", + old_field_name, + old_field_type, + new_field_name, + new_field_type)); + return false; + } + + // Since static fields have different flags than instance ones (specifically static fields must + // have the kAccStatic flag) we can tell if a field changes from static to instance. + if (new_iter.GetFieldAccessFlags() != old_iter.GetFieldAccessFlags()) { + RecordFailure(ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED), + StringPrintf("Field '%s' (sig: %s) had different access flags", + new_field_name, + new_field_type)); + return false; + } + + new_iter.Next(); + old_iter.Next(); + } + if (old_iter.HasNextInstanceField() || old_iter.HasNextStaticField()) { + RecordFailure(ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED), + StringPrintf("field '%s' (sig: %s) is missing!", + old_dex_file.GetFieldName(old_dex_file.GetFieldId( + old_iter.GetMemberIndex())), + old_dex_file.GetFieldTypeDescriptor(old_dex_file.GetFieldId( + old_iter.GetMemberIndex())))); + return false; + } + return true; +} + bool Redefiner::ClassRedefinition::CheckClass() { // TODO Might just want to put it in a ObjPtr and NoSuspend assert. art::StackHandleScope<1> hs(driver_->self_); diff --git a/runtime/openjdkjvmti/ti_redefine.h b/runtime/openjdkjvmti/ti_redefine.h index 5bcaef8971..749124fc49 100644 --- a/runtime/openjdkjvmti/ti_redefine.h +++ b/runtime/openjdkjvmti/ti_redefine.h @@ -170,17 +170,11 @@ class Redefiner { // Checks that the class can even be redefined. bool CheckRedefinable() REQUIRES_SHARED(art::Locks::mutator_lock_); - // Checks that the dex file does not add/remove methods. - bool CheckSameMethods() REQUIRES_SHARED(art::Locks::mutator_lock_) { - LOG(WARNING) << "methods are not checked for modification currently"; - return true; - } + // Checks that the dex file does not add/remove methods, or change their modifiers or types. + bool CheckSameMethods() REQUIRES_SHARED(art::Locks::mutator_lock_); - // Checks that the dex file does not modify fields - bool CheckSameFields() REQUIRES_SHARED(art::Locks::mutator_lock_) { - LOG(WARNING) << "Fields are not checked for modification currently"; - return true; - } + // Checks that the dex file does not modify fields types or modifiers. + bool CheckSameFields() REQUIRES_SHARED(art::Locks::mutator_lock_); void UpdateJavaDexFile(art::ObjPtr<art::mirror::Object> java_dex_file, art::ObjPtr<art::mirror::LongArray> new_cookie) diff --git a/test/921-hello-failure/expected.txt b/test/921-hello-failure/expected.txt index 9615e6b33d..e9b6a20cd6 100644 --- a/test/921-hello-failure/expected.txt +++ b/test/921-hello-failure/expected.txt @@ -29,3 +29,21 @@ hello2 - MultiRetrans Transformation error : java.lang.Exception(Failed to retransform classes <LTransform;, LTransform2;> due to JVMTI_ERROR_NAMES_DONT_MATCH) hello - MultiRetrans hello2 - MultiRetrans +hello - NewMethod +Transformation error : java.lang.Exception(Failed to redefine class <LTransform;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED) +hello - NewMethod +hello2 - MissingMethod +Transformation error : java.lang.Exception(Failed to redefine class <LTransform3;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED) +hello2 - MissingMethod +hello - MethodChange +Transformation error : java.lang.Exception(Failed to redefine class <LTransform;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED) +hello - MethodChange +hello - NewField +Transformation error : java.lang.Exception(Failed to redefine class <LTransform;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED) +hello - NewField +hello there - MissingField +Transformation error : java.lang.Exception(Failed to redefine class <LTransform4;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED) +hello there - MissingField +hello there again - FieldChange +Transformation error : java.lang.Exception(Failed to redefine class <LTransform4;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED) +hello there again - FieldChange diff --git a/test/921-hello-failure/src/FieldChange.java b/test/921-hello-failure/src/FieldChange.java new file mode 100644 index 0000000000..cc2ea284d9 --- /dev/null +++ b/test/921-hello-failure/src/FieldChange.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +import java.util.Base64; + +class FieldChange { + // The following is a base64 encoding of the following class. + // class Transform4 { + // private Object greeting; + // public Transform4(String hi) { } + // public void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFwoABgAQBwARCAASCgACABMHABQHABUBAAhncmVldGluZwEAEkxqYXZhL2xhbmcv" + + "T2JqZWN0OwEABjxpbml0PgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABENvZGUBAA9MaW5lTnVt" + + "YmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA9UcmFuc2Zvcm00LmphdmEMAAkAFgEAD2ph" + + "dmEvbGFuZy9FcnJvcgEAFVNob3VsZCBub3QgYmUgY2FsbGVkIQwACQAKAQAKVHJhbnNmb3JtNAEA" + + "EGphdmEvbGFuZy9PYmplY3QBAAMoKVYAIAAFAAYAAAABAAIABwAIAAAAAgABAAkACgABAAsAAAAd" + + "AAEAAgAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAMAAQANAAoAAQALAAAAIgADAAIAAAAKuwACWRID" + + "twAEvwAAAAEADAAAAAYAAQAAAAUAAQAOAAAAAgAP"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQASXs5yszuhud+/w4q07495k9eO7Yb+l8u4AgAAcAAAAHhWNBIAAAAAAAAAABgCAAAM" + + "AAAAcAAAAAUAAACgAAAAAgAAALQAAAABAAAAzAAAAAQAAADUAAAAAQAAAPQAAACkAQAAFAEAAFYB" + + "AABeAQAAbAEAAH8BAACTAQAApwEAAL4BAADPAQAA0gEAANYBAADqAQAA9AEAAAEAAAACAAAAAwAA" + + "AAQAAAAHAAAABwAAAAQAAAAAAAAACAAAAAQAAABQAQAAAAACAAoAAAAAAAEAAAAAAAAAAQALAAAA" + + "AQABAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAAcCAAAAAAAAAgACAAEAAAD7" + + "AQAABAAAAHAQAwAAAA4ABAACAAIAAAABAgAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMA" + + "Bjxpbml0PgAMTFRyYW5zZm9ybTQ7ABFMamF2YS9sYW5nL0Vycm9yOwASTGphdmEvbGFuZy9PYmpl" + + "Y3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAFVNob3VsZCBub3QgYmUgY2FsbGVkIQAPVHJhbnNmb3Jt" + + "NC5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00LjIyAAhncmVldGluZwAFc2F5SGkAAwEABw4A" + + "BQEABw4AAAEBAQACAIGABJQCAQGsAgANAAAAAAAAAAEAAAAAAAAAAQAAAAwAAABwAAAAAgAAAAUA" + + "AACgAAAAAwAAAAIAAAC0AAAABAAAAAEAAADMAAAABQAAAAQAAADUAAAABgAAAAEAAAD0AAAAASAA" + + "AAIAAAAUAQAAARAAAAEAAABQAQAAAiAAAAwAAABWAQAAAyAAAAIAAAD7AQAAACAAAAEAAAAHAgAA" + + "ABAAAAEAAAAYAgAA"); + + public static void doTest(Transform4 t) { + t.sayHi("FieldChange"); + try { + Main.doCommonClassRedefinition(Transform4.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("FieldChange"); + } +} diff --git a/test/921-hello-failure/src/Main.java b/test/921-hello-failure/src/Main.java index 67ca1e15d6..61d69e7396 100644 --- a/test/921-hello-failure/src/Main.java +++ b/test/921-hello-failure/src/Main.java @@ -25,6 +25,12 @@ public class Main { ReorderInterface.doTest(new Transform2()); MultiRedef.doTest(new Transform(), new Transform2()); MultiRetrans.doTest(new Transform(), new Transform2()); + NewMethod.doTest(new Transform()); + MissingMethod.doTest(new Transform3()); + MethodChange.doTest(new Transform()); + NewField.doTest(new Transform()); + MissingField.doTest(new Transform4("there")); + FieldChange.doTest(new Transform4("there again")); } // Transforms the class. This throws an exception if something goes wrong. diff --git a/test/921-hello-failure/src/MethodChange.java b/test/921-hello-failure/src/MethodChange.java new file mode 100644 index 0000000000..16f57788c8 --- /dev/null +++ b/test/921-hello-failure/src/MethodChange.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +import java.util.Base64; + +class MethodChange { + // The following is a base64 encoding of the following class. + // class Transform { + // void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFQoABgAPBwAQCAARCgACABIHABMHABQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAP" + + "TGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAApTb3VyY2VG" + + "aWxlAQAOVHJhbnNmb3JtLmphdmEMAAcACAEAD2phdmEvbGFuZy9FcnJvcgEAFVNob3VsZCBub3Qg" + + "YmUgY2FsbGVkIQwABwAMAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVjdAAgAAUABgAAAAAA" + + "AgAAAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAAAIAAAALAAwAAQAJAAAA" + + "IgADAAIAAAAKuwACWRIDtwAEvwAAAAEACgAAAAYAAQAAAAQAAQANAAAAAgAO"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQCrV81cy4Q+YKMMMqc0bZEO5Y1X5u7irPeQAgAAcAAAAHhWNBIAAAAAAAAAAPwBAAAL" + + "AAAAcAAAAAUAAACcAAAAAgAAALAAAAAAAAAAAAAAAAQAAADIAAAAAQAAAOgAAACIAQAACAEAAEoB" + + "AABSAQAAXwEAAHIBAACGAQAAmgEAALEBAADBAQAAxAEAAMgBAADcAQAAAQAAAAIAAAADAAAABAAA" + + "AAcAAAAHAAAABAAAAAAAAAAIAAAABAAAAEQBAAAAAAAAAAAAAAAAAQAKAAAAAQABAAAAAAACAAAA" + + "AAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAO4BAAAAAAAAAQABAAEAAADjAQAABAAAAHAQAwAA" + + "AA4ABAACAAIAAADoAQAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMABjxpbml0PgALTFRy" + + "YW5zZm9ybTsAEUxqYXZhL2xhbmcvRXJyb3I7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xh" + + "bmcvU3RyaW5nOwAVU2hvdWxkIG5vdCBiZSBjYWxsZWQhAA5UcmFuc2Zvcm0uamF2YQABVgACVkwA" + + "EmVtaXR0ZXI6IGphY2stNC4yNAAFc2F5SGkAAgAHDgAEAQAHDgAAAAEBAICABIgCAQCgAgwAAAAA" + + "AAAAAQAAAAAAAAABAAAACwAAAHAAAAACAAAABQAAAJwAAAADAAAAAgAAALAAAAAFAAAABAAAAMgA" + + "AAAGAAAAAQAAAOgAAAABIAAAAgAAAAgBAAABEAAAAQAAAEQBAAACIAAACwAAAEoBAAADIAAAAgAA" + + "AOMBAAAAIAAAAQAAAO4BAAAAEAAAAQAAAPwBAAA="); + + public static void doTest(Transform t) { + t.sayHi("MethodChange"); + try { + Main.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("MethodChange"); + } +} diff --git a/test/921-hello-failure/src/MissingField.java b/test/921-hello-failure/src/MissingField.java new file mode 100644 index 0000000000..2f643cc871 --- /dev/null +++ b/test/921-hello-failure/src/MissingField.java @@ -0,0 +1,58 @@ +/* + * 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. + */ + +import java.util.Base64; + +class MissingField { + // The following is a base64 encoding of the following class. + // class Transform4 { + // public Transform4(String s) { } + // public void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFQoABgAOBwAPCAAQCgACABEHABIHABMBAAY8aW5pdD4BABUoTGphdmEvbGFuZy9T" + + "dHJpbmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAFc2F5SGkBAApTb3VyY2VGaWxlAQAP" + + "VHJhbnNmb3JtNC5qYXZhDAAHABQBAA9qYXZhL2xhbmcvRXJyb3IBABVTaG91bGQgbm90IGJlIGNh" + + "bGxlZCEMAAcACAEAClRyYW5zZm9ybTQBABBqYXZhL2xhbmcvT2JqZWN0AQADKClWACAABQAGAAAA" + + "AAACAAEABwAIAAEACQAAAB0AAQACAAAABSq3AAGxAAAAAQAKAAAABgABAAAAAgABAAsACAABAAkA" + + "AAAiAAMAAgAAAAq7AAJZEgO3AAS/AAAAAQAKAAAABgABAAAABAABAAwAAAACAA0="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQDBVUVrMUEFx3lYkgJF54evq9vHvOUDZveUAgAAcAAAAHhWNBIAAAAAAAAAAAACAAAL" + + "AAAAcAAAAAUAAACcAAAAAgAAALAAAAAAAAAAAAAAAAQAAADIAAAAAQAAAOgAAACMAQAACAEAAEoB" + + "AABSAQAAYAEAAHMBAACHAQAAmwEAALIBAADDAQAAxgEAAMoBAADeAQAAAQAAAAIAAAADAAAABAAA" + + "AAcAAAAHAAAABAAAAAAAAAAIAAAABAAAAEQBAAAAAAEAAAAAAAAAAQAKAAAAAQABAAAAAAACAAAA" + + "AAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAPEBAAAAAAAAAgACAAEAAADlAQAABAAAAHAQAwAA" + + "AA4ABAACAAIAAADrAQAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMABjxpbml0PgAMTFRy" + + "YW5zZm9ybTQ7ABFMamF2YS9sYW5nL0Vycm9yOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9s" + + "YW5nL1N0cmluZzsAFVNob3VsZCBub3QgYmUgY2FsbGVkIQAPVHJhbnNmb3JtNC5qYXZhAAFWAAJW" + + "TAASZW1pdHRlcjogamFjay00LjIyAAVzYXlIaQACAQAHDgAEAQAHDgAAAAEBAIGABIgCAQGgAgAM" + + "AAAAAAAAAAEAAAAAAAAAAQAAAAsAAABwAAAAAgAAAAUAAACcAAAAAwAAAAIAAACwAAAABQAAAAQA" + + "AADIAAAABgAAAAEAAADoAAAAASAAAAIAAAAIAQAAARAAAAEAAABEAQAAAiAAAAsAAABKAQAAAyAA" + + "AAIAAADlAQAAACAAAAEAAADxAQAAABAAAAEAAAAAAgAA"); + + public static void doTest(Transform4 t) { + t.sayHi("MissingField"); + try { + Main.doCommonClassRedefinition(Transform4.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("MissingField"); + } +} diff --git a/test/921-hello-failure/src/MissingMethod.java b/test/921-hello-failure/src/MissingMethod.java new file mode 100644 index 0000000000..3f1925c9ad --- /dev/null +++ b/test/921-hello-failure/src/MissingMethod.java @@ -0,0 +1,57 @@ +/* + * 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. + */ + +import java.util.Base64; + +class MissingMethod { + // The following is a base64 encoding of the following class. + // class Transform3 { + // public void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFQoABgAPBwAQCAARCgACABIHABMHABQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAP" + + "TGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAApTb3VyY2VG" + + "aWxlAQAPVHJhbnNmb3JtMy5qYXZhDAAHAAgBAA9qYXZhL2xhbmcvRXJyb3IBABVTaG91bGQgbm90" + + "IGJlIGNhbGxlZCEMAAcADAEAClRyYW5zZm9ybTMBABBqYXZhL2xhbmcvT2JqZWN0ACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAAgABAAsADAABAAkA" + + "AAAiAAMAAgAAAAq7AAJZEgO3AAS/AAAAAQAKAAAABgABAAAABAABAA0AAAACAA4="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQDnVQvyn7XrwDiCC/SE55zBCtEqk4pzA2mUAgAAcAAAAHhWNBIAAAAAAAAAAAACAAAL" + + "AAAAcAAAAAUAAACcAAAAAgAAALAAAAAAAAAAAAAAAAQAAADIAAAAAQAAAOgAAACMAQAACAEAAEoB" + + "AABSAQAAYAEAAHMBAACHAQAAmwEAALIBAADDAQAAxgEAAMoBAADeAQAAAQAAAAIAAAADAAAABAAA" + + "AAcAAAAHAAAABAAAAAAAAAAIAAAABAAAAEQBAAAAAAAAAAAAAAAAAQAKAAAAAQABAAAAAAACAAAA" + + "AAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAPABAAAAAAAAAQABAAEAAADlAQAABAAAAHAQAwAA" + + "AA4ABAACAAIAAADqAQAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMABjxpbml0PgAMTFRy" + + "YW5zZm9ybTM7ABFMamF2YS9sYW5nL0Vycm9yOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9s" + + "YW5nL1N0cmluZzsAFVNob3VsZCBub3QgYmUgY2FsbGVkIQAPVHJhbnNmb3JtMy5qYXZhAAFWAAJW" + + "TAASZW1pdHRlcjogamFjay00LjI0AAVzYXlIaQACAAcOAAQBAAcOAAAAAQEAgIAEiAIBAaACAAAM" + + "AAAAAAAAAAEAAAAAAAAAAQAAAAsAAABwAAAAAgAAAAUAAACcAAAAAwAAAAIAAACwAAAABQAAAAQA" + + "AADIAAAABgAAAAEAAADoAAAAASAAAAIAAAAIAQAAARAAAAEAAABEAQAAAiAAAAsAAABKAQAAAyAA" + + "AAIAAADlAQAAACAAAAEAAADwAQAAABAAAAEAAAAAAgAA"); + + public static void doTest(Transform3 t) { + t.sayHi("MissingMethod"); + try { + Main.doCommonClassRedefinition(Transform3.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("MissingMethod"); + } +} diff --git a/test/921-hello-failure/src/NewField.java b/test/921-hello-failure/src/NewField.java new file mode 100644 index 0000000000..c85b79e824 --- /dev/null +++ b/test/921-hello-failure/src/NewField.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +import java.util.Base64; + +class NewField { + // The following is a base64 encoding of the following class. + // class Transform { + // private Object field; + // public void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFwoABgARBwASCAATCgACABQHABUHABYBAAVmaWVsZAEAEkxqYXZhL2xhbmcvT2Jq" + + "ZWN0OwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAFShM" + + "amF2YS9sYW5nL1N0cmluZzspVgEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwACQAKAQAP" + + "amF2YS9sYW5nL0Vycm9yAQAVU2hvdWxkIG5vdCBiZSBjYWxsZWQhDAAJAA4BAAlUcmFuc2Zvcm0B" + + "ABBqYXZhL2xhbmcvT2JqZWN0ACAABQAGAAAAAQACAAcACAAAAAIAAAAJAAoAAQALAAAAHQABAAEA" + + "AAAFKrcAAbEAAAABAAwAAAAGAAEAAAABAAEADQAOAAEACwAAACIAAwACAAAACrsAAlkSA7cABL8A" + + "AAABAAwAAAAGAAEAAAAEAAEADwAAAAIAEA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBNWknL2iyjim487p0EIH/8V5OjOeLgw5e0AgAAcAAAAHhWNBIAAAAAAAAAABQCAAAM" + + "AAAAcAAAAAUAAACgAAAAAgAAALQAAAABAAAAzAAAAAQAAADUAAAAAQAAAPQAAACgAQAAFAEAAFYB" + + "AABeAQAAawEAAH4BAACSAQAApgEAAL0BAADNAQAA0AEAANQBAADoAQAA7wEAAAEAAAACAAAAAwAA" + + "AAQAAAAHAAAABwAAAAQAAAAAAAAACAAAAAQAAABQAQAAAAACAAoAAAAAAAAAAAAAAAAAAQALAAAA" + + "AQABAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAAECAAAAAAAAAQABAAEAAAD2" + + "AQAABAAAAHAQAwAAAA4ABAACAAIAAAD7AQAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMA" + + "Bjxpbml0PgALTFRyYW5zZm9ybTsAEUxqYXZhL2xhbmcvRXJyb3I7ABJMamF2YS9sYW5nL09iamVj" + + "dDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAVU2hvdWxkIG5vdCBiZSBjYWxsZWQhAA5UcmFuc2Zvcm0u" + + "amF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2stNC4yMgAFZmllbGQABXNheUhpAAEABw4ABAEABw4A" + + "AAEBAQACAICABJQCAQGsAgAAAA0AAAAAAAAAAQAAAAAAAAABAAAADAAAAHAAAAACAAAABQAAAKAA" + + "AAADAAAAAgAAALQAAAAEAAAAAQAAAMwAAAAFAAAABAAAANQAAAAGAAAAAQAAAPQAAAABIAAAAgAA" + + "ABQBAAABEAAAAQAAAFABAAACIAAADAAAAFYBAAADIAAAAgAAAPYBAAAAIAAAAQAAAAECAAAAEAAA" + + "AQAAABQCAAA="); + + public static void doTest(Transform t) { + t.sayHi("NewField"); + try { + Main.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("NewField"); + } +} diff --git a/test/921-hello-failure/src/NewMethod.java b/test/921-hello-failure/src/NewMethod.java new file mode 100644 index 0000000000..5eac670c68 --- /dev/null +++ b/test/921-hello-failure/src/NewMethod.java @@ -0,0 +1,60 @@ +/* + * 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. + */ + +import java.util.Base64; + +class NewMethod { + // The following is a base64 encoding of the following class. + // class Transform { + // public void extraMethod() {} + // public void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFgoABgAQBwARCAASCgACABMHABQHABUBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAP" + + "TGluZU51bWJlclRhYmxlAQALZXh0cmFNZXRob2QBAAVzYXlIaQEAFShMamF2YS9sYW5nL1N0cmlu" + + "ZzspVgEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwABwAIAQAPamF2YS9sYW5nL0Vycm9y" + + "AQAVU2hvdWxkIG5vdCBiZSBjYWxsZWQhDAAHAA0BAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + + "ZWN0ACAABQAGAAAAAAADAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAA" + + "AQABAAsACAABAAkAAAAZAAAAAQAAAAGxAAAAAQAKAAAABgABAAAAAgABAAwADQABAAkAAAAiAAMA" + + "AgAAAAq7AAJZEgO3AAS/AAAAAQAKAAAABgABAAAABAABAA4AAAACAA8="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBeV7dLAwN1GBTa/yRlkuiIQatNHghVdrnIAgAAcAAAAHhWNBIAAAAAAAAAADQCAAAM" + + "AAAAcAAAAAUAAACgAAAAAgAAALQAAAAAAAAAAAAAAAUAAADMAAAAAQAAAPQAAAC0AQAAFAEAAGoB" + + "AAByAQAAfwEAAJIBAACmAQAAugEAANEBAADhAQAA5AEAAOgBAAD8AQAACQIAAAEAAAACAAAAAwAA" + + "AAQAAAAHAAAABwAAAAQAAAAAAAAACAAAAAQAAABkAQAAAAAAAAAAAAAAAAAACgAAAAAAAQALAAAA" + + "AQABAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAACACAAAAAAAAAQABAAEAAAAQ" + + "AgAABAAAAHAQBAAAAA4AAQABAAAAAAAVAgAAAQAAAA4AAAAEAAIAAgAAABoCAAAJAAAAIgABABsB" + + "BQAAAHAgAwAQACcAAAABAAAAAwAGPGluaXQ+AAtMVHJhbnNmb3JtOwARTGphdmEvbGFuZy9FcnJv" + + "cjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABVTaG91bGQgbm90IGJl" + + "IGNhbGxlZCEADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00LjIyAAtleHRy" + + "YU1ldGhvZAAFc2F5SGkAAQAHDgACAAcOAAQBAAcOAAAAAQIAgIAElAIBAawCAQHAAgAADAAAAAAA" + + "AAABAAAAAAAAAAEAAAAMAAAAcAAAAAIAAAAFAAAAoAAAAAMAAAACAAAAtAAAAAUAAAAFAAAAzAAA" + + "AAYAAAABAAAA9AAAAAEgAAADAAAAFAEAAAEQAAABAAAAZAEAAAIgAAAMAAAAagEAAAMgAAADAAAA" + + "EAIAAAAgAAABAAAAIAIAAAAQAAABAAAANAIAAA=="); + + public static void doTest(Transform t) { + t.sayHi("NewMethod"); + try { + Main.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("NewMethod"); + } +} diff --git a/test/921-hello-failure/src/Transform3.java b/test/921-hello-failure/src/Transform3.java new file mode 100644 index 0000000000..d2cb064956 --- /dev/null +++ b/test/921-hello-failure/src/Transform3.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +class Transform3 { + public void extraMethod(String name) { + System.out.println("extraMethod - " + name); + } + public void sayHi(String name) { + System.out.println("hello2 - " + name); + } +} diff --git a/test/921-hello-failure/src/Transform4.java b/test/921-hello-failure/src/Transform4.java new file mode 100644 index 0000000000..fd763386ba --- /dev/null +++ b/test/921-hello-failure/src/Transform4.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +class Transform4 { + private String greeting; + public Transform4(String hi) { + greeting = hi; + } + public void sayHi(String name) { + System.out.println("hello " + greeting + " - " + name); + } +} diff --git a/test/942-private-recursive/src/Transform.java b/test/942-private-recursive/src/Transform.java index dd5452cac8..7714326066 100644 --- a/test/942-private-recursive/src/Transform.java +++ b/test/942-private-recursive/src/Transform.java @@ -15,10 +15,6 @@ */ class Transform { - public void sayHi(int recur, Runnable r) { - privateSayHi(recur, r); - } - private void privateSayHi(int recur, Runnable r) { System.out.println("hello" + recur); if (recur == 1) { @@ -29,4 +25,8 @@ class Transform { } System.out.println("goodbye" + recur); } + + public void sayHi(int recur, Runnable r) { + privateSayHi(recur, r); + } } |