Check for duplicate entries when using dexlayout

The previous approach always inserted in the CollectionMap. This did
not work correctly if two different objects had the same offset. Since
we constructed a unique_ptr of the object, it would simply get freed
if the insert failed because there was already an object with the same
offset.

This meant that there were some use after free errors for these
objects.

Test: dexlayout -a -b hulu.apk

Bug: 35305951
Change-Id: I217e6d83bf6e051b13b1a601ec25512f40593880
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index b1e66be3..43de342 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -588,11 +588,14 @@
   const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(&disk_code_item);
   DebugInfoItem* debug_info = nullptr;
   if (debug_info_stream != nullptr) {
-    uint32_t debug_info_size = GetDebugInfoStreamSize(debug_info_stream);
-    uint8_t* debug_info_buffer = new uint8_t[debug_info_size];
-    memcpy(debug_info_buffer, debug_info_stream, debug_info_size);
-    debug_info = new DebugInfoItem(debug_info_size, debug_info_buffer);
-    debug_info_items_.AddItem(debug_info, disk_code_item.debug_info_off_);
+    debug_info = debug_info_items_.GetExistingObject(disk_code_item.debug_info_off_);
+    if (debug_info == nullptr) {
+      uint32_t debug_info_size = GetDebugInfoStreamSize(debug_info_stream);
+      uint8_t* debug_info_buffer = new uint8_t[debug_info_size];
+      memcpy(debug_info_buffer, debug_info_stream, debug_info_size);
+      debug_info = new DebugInfoItem(debug_info_size, debug_info_buffer);
+      debug_info_items_.AddItem(debug_info, disk_code_item.debug_info_off_);
+    }
   }
 
   uint32_t insns_size = disk_code_item.insns_size_in_code_units_;
@@ -683,8 +686,8 @@
     const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset) {
   // Read the fields and methods defined by the class, resolving the circular reference from those
   // to classes by setting class at the same time.
-  ClassData* class_data = nullptr;
-  if (encoded_data != nullptr) {
+  ClassData* class_data = class_datas_.GetExistingObject(offset);
+  if (class_data == nullptr && encoded_data != nullptr) {
     ClassDataItemIterator cdii(dex_file, encoded_data);
     // Static fields.
     FieldItemVector* static_fields = new FieldItemVector();
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index e2ee940..3a5b644 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -134,9 +134,17 @@
  public:
   CollectionMap() = default;
 
+  // Returns the existing item if it is already inserted, null otherwise.
+  T* GetExistingObject(uint32_t offset) {
+    auto it = collection_.find(offset);
+    return it != collection_.end() ? it->second.get() : nullptr;
+  }
+
   void AddItem(T* object, uint32_t offset) {
     object->SetOffset(offset);
-    collection_.emplace(offset, std::unique_ptr<T>(object));
+    auto it = collection_.emplace(offset, std::unique_ptr<T>(object));
+    CHECK(it.second) << "CollectionMap already has an object with offset " << offset << " "
+                     << " and address " << it.first->second.get();
   }
   uint32_t Size() const { return collection_.size(); }
   std::map<uint32_t, std::unique_ptr<T>>& Collection() { return collection_; }