Merge "Avoid re-mapping dex file that's in local memory."
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index bf63abf..8fc3d23 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -50,6 +50,22 @@
 
 std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory,
                                          MapInfo* info) {
+  if (UNLIKELY(!HasDexSupport())) {
+    return nullptr;
+  }
+
+  size_t max_size = info->end - dex_file_offset_in_memory;
+  if (memory->IsLocal()) {
+    size_t size = max_size;
+
+    std::string err_msg;
+    std::unique_ptr<art_api::dex::DexFile> art_dex_file = DexFile::OpenFromMemory(
+        reinterpret_cast<void const*>(dex_file_offset_in_memory), &size, info->name, &err_msg);
+    if (art_dex_file != nullptr && size <= max_size) {
+      return std::unique_ptr<DexFile>(new DexFile(art_dex_file));
+    }
+  }
+
   if (!info->name.empty()) {
     std::unique_ptr<DexFile> dex_file =
         DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name);
@@ -57,7 +73,7 @@
       return dex_file;
     }
   }
-  return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
+  return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name, max_size);
 }
 
 bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
@@ -94,7 +110,8 @@
 
 std::unique_ptr<DexFileFromMemory> DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory,
                                                              Memory* memory,
-                                                             const std::string& name) {
+                                                             const std::string& name,
+                                                             size_t max_size) {
   if (UNLIKELY(!HasDexSupport())) {
     return nullptr;
   }
@@ -105,6 +122,9 @@
     std::string error_msg;
     std::unique_ptr<art_api::dex::DexFile> art_dex_file =
         OpenFromMemory(backing_memory.data(), &size, name, &error_msg);
+    if (size > max_size) {
+      return nullptr;
+    }
 
     if (art_dex_file != nullptr) {
       return std::unique_ptr<DexFileFromMemory>(
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index 4e8369f..fe185da 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -55,7 +55,8 @@
 class DexFileFromMemory : public DexFile {
  public:
   static std::unique_ptr<DexFileFromMemory> Create(uint64_t dex_file_offset_in_memory,
-                                                   Memory* memory, const std::string& name);
+                                                   Memory* memory, const std::string& name,
+                                                   size_t max_size);
 
  private:
   DexFileFromMemory(std::unique_ptr<art_api::dex::DexFile>& art_dex_file,
diff --git a/libunwindstack/MemoryLocal.h b/libunwindstack/MemoryLocal.h
index 29aaf12..7e027cf 100644
--- a/libunwindstack/MemoryLocal.h
+++ b/libunwindstack/MemoryLocal.h
@@ -28,6 +28,8 @@
   MemoryLocal() = default;
   virtual ~MemoryLocal() = default;
 
+  bool IsLocal() const override { return true; }
+
   size_t Read(uint64_t addr, void* dst, size_t size) override;
 };
 
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 3106564..ecd908a 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -41,6 +41,8 @@
 
   virtual void Clear() {}
 
+  virtual bool IsLocal() const { return false; }
+
   virtual size_t Read(uint64_t addr, void* dst, size_t size) = 0;
 
   bool ReadFully(uint64_t addr, void* dst, size_t size);
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index dc935a3..1deba01 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -21,6 +21,7 @@
 
 #include <unordered_map>
 
+#include <MemoryLocal.h>
 #include <android-base/file.h>
 #include <gtest/gtest.h>
 #include <unwindstack/MapInfo.h>
@@ -109,7 +110,7 @@
 
   memory.SetMemory(0x1000, kDexData, 10);
 
-  EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr);
+  EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "", sizeof(kDexData)) == nullptr);
 }
 
 TEST(DexFileTest, from_memory_fail_too_small_for_data) {
@@ -117,7 +118,7 @@
 
   memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
 
-  EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr);
+  EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "", sizeof(kDexData)) == nullptr);
 }
 
 TEST(DexFileTest, from_memory_open) {
@@ -125,7 +126,7 @@
 
   memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
 
-  EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") != nullptr);
+  EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "", sizeof(kDexData)) != nullptr);
 }
 
 TEST(DexFileTest, from_memory_no_leak) {
@@ -136,7 +137,7 @@
   size_t first_allocated_bytes = 0;
   size_t last_allocated_bytes = 0;
   for (size_t i = 0; i < kNumLeakLoops; i++) {
-    EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") != nullptr);
+    EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "", sizeof(kDexData)) != nullptr);
     ASSERT_NO_FATAL_FAILURE(CheckForLeak(i, &first_allocated_bytes, &last_allocated_bytes));
   }
 }
@@ -213,6 +214,43 @@
   EXPECT_TRUE(dex_file == nullptr);
 }
 
+TEST(DexFileTest, create_using_memory_size_too_small) {
+  MemoryFake memory;
+  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
+  MapInfo info(nullptr, nullptr, 0x100, sizeof(kDexData) - 2, 0x200, 0x5, "/does/not/exist");
+  EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr);
+}
+
+class MemoryLocalFake : public MemoryLocal {
+ public:
+  MemoryLocalFake(size_t memory_size) : backing_(memory_size) {}
+  virtual ~MemoryLocalFake() = default;
+
+  void* Data() { return backing_.data(); }
+
+ private:
+  std::vector<void*> backing_;
+};
+
+TEST(DexFileTest, create_using_local_memory) {
+  MemoryLocalFake memory(sizeof(kDexData));
+
+  memcpy(memory.Data(), kDexData, sizeof(kDexData));
+  uint64_t start = reinterpret_cast<uint64_t>(memory.Data());
+  MapInfo info(nullptr, nullptr, start, start + 0x1000, 0x200, 0x5, "/does/not/exist");
+  EXPECT_TRUE(DexFile::Create(start, &memory, &info) != nullptr);
+}
+
+TEST(DexFileTest, create_using_local_memory_size_too_small) {
+  MemoryLocalFake memory(sizeof(kDexData));
+
+  memcpy(memory.Data(), kDexData, sizeof(kDexData));
+  uint64_t start = reinterpret_cast<uint64_t>(memory.Data());
+  MapInfo info(nullptr, nullptr, start, start + sizeof(kDexData) - 2, 0x200, 0x5,
+               "/does/not/exist");
+  EXPECT_TRUE(DexFile::Create(start, &memory, &info) == nullptr);
+}
+
 TEST(DexFileTest, get_method) {
   MemoryFake memory;
   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));