summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alex Light <allight@google.com> 2018-01-26 15:45:30 -0800
committer Alex Light <allight@google.com> 2018-01-29 19:42:40 +0000
commit1a824a5c1070648971ce9593a1dd71cdd8cf2f98 (patch)
tree1ff6d9fd284a4dd2a337165dff20e71137997c9d
parent0406e1e59970399393f53923704e1b9a828b2173 (diff)
Remove hiddenapi access flags in FixedUpDexFile
The hiddenapi tool will mess with the access flags of fields and methods in order to record which are '@hide'. We need to undo this before passing any dex files down to jvmti agents. Test: ./test.py --host -j50 Bug: 72550707 Bug: 64382372 Change-Id: Ibc9a96a6b541c06844f276db009ac29514f7a3bb
-rw-r--r--openjdkjvmti/fixed_up_dex_file.cc16
-rw-r--r--runtime/leb128.h32
-rw-r--r--runtime/vdex_file.cc57
-rw-r--r--test/983-source-transform-verify/expected.txt1
-rw-r--r--test/983-source-transform-verify/src/art/Test983.java4
-rw-r--r--tools/hiddenapi/hiddenapi.cc38
6 files changed, 93 insertions, 55 deletions
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index 6c66f12bb1..a8d2a37fa6 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -33,6 +33,7 @@
#include "dex/art_dex_file_loader.h"
#include "dex/dex_file-inl.h"
#include "dex/dex_file_loader.h"
+#include "dex/dex_file_verifier.h"
// Runtime includes.
#include "dex_container.h"
@@ -67,6 +68,20 @@ static void DoDexUnquicken(const art::DexFile& new_dex_file, const art::DexFile&
vdex->UnquickenDexFile(new_dex_file, original_dex_file, /* decompile_return_instruction */true);
}
+static void DCheckVerifyDexFile(const art::DexFile& dex) {
+ if (art::kIsDebugBuild) {
+ std::string error;
+ if (!art::DexFileVerifier::Verify(&dex,
+ dex.Begin(),
+ dex.Size(),
+ "FixedUpDexFile_Verification.dex",
+ /*verify_checksum*/ true,
+ &error)) {
+ LOG(FATAL) << "Failed to verify de-quickened dex file: " << error;
+ }
+ }
+}
+
std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original,
const char* descriptor) {
// Copy the data into mutable memory.
@@ -121,6 +136,7 @@ std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& origi
DoDexUnquicken(*new_dex_file, original);
RecomputeDexChecksum(const_cast<art::DexFile*>(new_dex_file.get()));
+ DCheckVerifyDexFile(*new_dex_file);
std::unique_ptr<FixedUpDexFile> ret(new FixedUpDexFile(std::move(new_dex_file), std::move(data)));
return ret;
}
diff --git a/runtime/leb128.h b/runtime/leb128.h
index 9fb09d8fc2..07eadc1ddf 100644
--- a/runtime/leb128.h
+++ b/runtime/leb128.h
@@ -55,6 +55,10 @@ static inline uint32_t DecodeUnsignedLeb128(const uint8_t** data) {
return static_cast<uint32_t>(result);
}
+static inline uint32_t DecodeUnsignedLeb128WithoutMovingCursor(const uint8_t* data) {
+ return DecodeUnsignedLeb128(&data);
+}
+
static inline bool DecodeUnsignedLeb128Checked(const uint8_t** data,
const void* end,
uint32_t* out) {
@@ -203,6 +207,34 @@ static inline uint32_t UnsignedLeb128Size(uint32_t data) {
return (x * 37) >> 8;
}
+static inline bool IsLeb128Terminator(const uint8_t* ptr) {
+ return *ptr <= 0x7f;
+}
+
+// Returns the first byte of a Leb128 value assuming that:
+// (1) `end_ptr` points to the first byte after the Leb128 value, and
+// (2) there is another Leb128 value before this one.
+template <typename T>
+static inline T* ReverseSearchUnsignedLeb128(T* end_ptr) {
+ static_assert(std::is_same<typename std::remove_const<T>::type, uint8_t>::value,
+ "T must be a uint8_t");
+ T* ptr = end_ptr;
+
+ // Move one byte back, check that this is the terminating byte.
+ ptr--;
+ DCHECK(IsLeb128Terminator(ptr));
+
+ // Keep moving back while the previous byte is not a terminating byte.
+ // Fail after reading five bytes in case there isn't another Leb128 value
+ // before this one.
+ while (!IsLeb128Terminator(ptr - 1)) {
+ ptr--;
+ DCHECK_LE(static_cast<ptrdiff_t>(end_ptr - ptr), 5);
+ }
+
+ return ptr;
+}
+
// Returns the number of bytes needed to encode the value in unsigned LEB128.
static inline uint32_t SignedLeb128Size(int32_t data) {
// Like UnsignedLeb128Size(), but we need one bit beyond the highest bit that differs from sign.
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 36ebb17f4f..7428e98dbb 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -30,6 +30,8 @@
#include "dex/dex_file.h"
#include "dex/dex_file_loader.h"
#include "dex_to_dex_decompiler.h"
+#include "hidden_api_access_flags.h"
+#include "leb128.h"
#include "quicken_info.h"
namespace art {
@@ -262,6 +264,18 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
UnquickenDexFile(target_dex_file, source_dex_file.Begin(), decompile_return_instruction);
}
+static void UpdateAccessFlags(uint8_t* data, uint32_t new_flag, bool is_method) {
+ // Go back 1 uleb to start.
+ data = ReverseSearchUnsignedLeb128(data);
+ if (is_method) {
+ // Methods have another uleb field before the access flags
+ data = ReverseSearchUnsignedLeb128(data);
+ }
+ DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data)),
+ new_flag);
+ UpdateUnsignedLeb128(data, new_flag);
+}
+
void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
const uint8_t* source_dex_begin,
bool decompile_return_instruction) const {
@@ -280,27 +294,32 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file,
for (ClassDataItemIterator class_it(target_dex_file, class_data);
class_it.HasNext();
class_it.Next()) {
- if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
+ if (class_it.IsAtMethod()) {
const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem();
- if (!unquickened_code_item.emplace(code_item).second) {
- // Already unquickened this code item, do not do it again.
- continue;
- }
- ArrayRef<const uint8_t> quicken_data;
- if (!quickening_info.empty()) {
- const uint32_t quickening_offset = GetQuickeningInfoOffset(
- GetQuickenInfoOffsetTable(source_dex_begin,
- target_dex_file.NumMethodIds(),
- quickening_info),
- class_it.GetMemberIndex(),
- quickening_info);
- quicken_data = GetQuickeningInfoAt(quickening_info, quickening_offset);
+ if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) {
+ ArrayRef<const uint8_t> quicken_data;
+ if (!quickening_info.empty()) {
+ const uint32_t quickening_offset = GetQuickeningInfoOffset(
+ GetQuickenInfoOffsetTable(source_dex_begin,
+ target_dex_file.NumMethodIds(),
+ quickening_info),
+ class_it.GetMemberIndex(),
+ quickening_info);
+ quicken_data = GetQuickeningInfoAt(quickening_info, quickening_offset);
+ }
+ optimizer::ArtDecompileDEX(
+ target_dex_file,
+ *code_item,
+ quicken_data,
+ decompile_return_instruction);
}
- optimizer::ArtDecompileDEX(
- target_dex_file,
- *code_item,
- quicken_data,
- decompile_return_instruction);
+ UpdateAccessFlags(const_cast<uint8_t*>(class_it.DataPointer()),
+ class_it.GetMemberAccessFlags(),
+ /*is_method*/ true);
+ } else {
+ UpdateAccessFlags(const_cast<uint8_t*>(class_it.DataPointer()),
+ class_it.GetMemberAccessFlags(),
+ /*is_method*/ false);
}
}
}
diff --git a/test/983-source-transform-verify/expected.txt b/test/983-source-transform-verify/expected.txt
index abcdf3a868..aa51ea08ae 100644
--- a/test/983-source-transform-verify/expected.txt
+++ b/test/983-source-transform-verify/expected.txt
@@ -1,2 +1,3 @@
Dex file hook for art/Test983$Transform
Dex file hook for java/lang/Object
+Dex file hook for java/lang/ClassLoader
diff --git a/test/983-source-transform-verify/src/art/Test983.java b/test/983-source-transform-verify/src/art/Test983.java
index b81e7f4df3..faae96aef6 100644
--- a/test/983-source-transform-verify/src/art/Test983.java
+++ b/test/983-source-transform-verify/src/art/Test983.java
@@ -16,7 +16,6 @@
package art;
-import java.util.Base64;
public class Test983 {
static class Transform {
public void sayHi() {
@@ -29,10 +28,11 @@ public class Test983 {
}
public static void doTest() {
- Transform abc = new Transform();
Redefinition.enableCommonRetransformation(true);
Redefinition.doCommonClassRetransformation(Transform.class);
Redefinition.doCommonClassRetransformation(Object.class);
+ // NB java.lang.ClassLoader has hidden fields.
+ Redefinition.doCommonClassRetransformation(ClassLoader.class);
Redefinition.enableCommonRetransformation(false);
}
}
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index a755fdb40b..c893da646d 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -118,9 +118,11 @@ class DexMember {
// until we hit the terminating byte of the previous Leb128 value.
const uint8_t* ptr = it_.DataPointer();
if (it_.IsAtMethod()) {
- ptr = ReverseSearchUnsignedLeb128(ptr, it_.GetMethodCodeItemOffset());
+ ptr = ReverseSearchUnsignedLeb128(ptr);
+ DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), it_.GetMethodCodeItemOffset());
}
- ptr = ReverseSearchUnsignedLeb128(ptr, old_flags);
+ ptr = ReverseSearchUnsignedLeb128(ptr);
+ DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), old_flags);
// Overwrite the access flags.
UpdateUnsignedLeb128(const_cast<uint8_t*>(ptr), new_flags);
@@ -158,38 +160,6 @@ class DexMember {
return klass_.GetDexFile().GetFieldId(it_.GetMemberIndex());
}
- static inline bool IsLeb128Terminator(const uint8_t* ptr) {
- return *ptr <= 0x7f;
- }
-
- // Returns the first byte of a Leb128 value assuming that:
- // (1) `end_ptr` points to the first byte after the Leb128 value, and
- // (2) there is another Leb128 value before this one.
- // The function will fail after reading 5 bytes (the longest supported Leb128
- // encoding) to protect against situations when (2) is not satisfied.
- // When a Leb128 value is discovered, it is decoded and CHECKed against `value`.
- static const uint8_t* ReverseSearchUnsignedLeb128(const uint8_t* end_ptr, uint32_t expected) {
- const uint8_t* ptr = end_ptr;
-
- // Move one byte back, check that this is the terminating byte.
- ptr--;
- CHECK(IsLeb128Terminator(ptr));
-
- // Keep moving back while the previous byte is not a terminating byte.
- // Fail after reading five bytes in case there isn't another Leb128 value
- // before this one.
- while (!IsLeb128Terminator(ptr - 1)) {
- ptr--;
- CHECK_LE((size_t) (end_ptr - ptr), 5u);
- }
-
- // Check that the decoded value matches the `expected` value.
- const uint8_t* tmp_ptr = ptr;
- CHECK_EQ(DecodeUnsignedLeb128(&tmp_ptr), expected);
-
- return ptr;
- }
-
const DexClass& klass_;
const ClassDataItemIterator& it_;
};