Add custom arena deleter for RegisterLine

Previously it protected by using sizeof(RegisterLine) but this was
not accurate due to register lines being variable sized.

Bug: 27156726
Change-Id: Ia4b134b85a2e61993d17bd4f0eff60c89c164dc3
diff --git a/runtime/base/scoped_arena_containers.h b/runtime/base/scoped_arena_containers.h
index 1236585..9b56856 100644
--- a/runtime/base/scoped_arena_containers.h
+++ b/runtime/base/scoped_arena_containers.h
@@ -201,22 +201,28 @@
 template <typename T>
 class ArenaDelete {
   static constexpr uint8_t kMagicFill = 0xCE;
- public:
-  void operator()(T* ptr) const {
-    ptr->~T();
+ protected:
+  // Used for variable sized objects such as RegisterLine.
+  ALWAYS_INLINE void ProtectMemory(T* ptr, size_t size) const {
     if (RUNNING_ON_MEMORY_TOOL > 0) {
       // Writing to the memory will fail if it we already destroyed the pointer with
       // DestroyOnlyDelete since we make it no access.
-      memset(ptr, kMagicFill, sizeof(T));
-      MEMORY_TOOL_MAKE_NOACCESS(ptr, sizeof(T));
+      memset(ptr, kMagicFill, size);
+      MEMORY_TOOL_MAKE_NOACCESS(ptr, size);
     } else if (kIsDebugBuild) {
       CHECK(ArenaStack::ArenaTagForAllocation(reinterpret_cast<void*>(ptr)) == ArenaFreeTag::kUsed)
           << "Freeing invalid object " << ptr;
       ArenaStack::ArenaTagForAllocation(reinterpret_cast<void*>(ptr)) = ArenaFreeTag::kFree;
       // Write a magic value to try and catch use after free error.
-      memset(ptr, kMagicFill, sizeof(T));
+      memset(ptr, kMagicFill, size);
     }
   }
+
+ public:
+  void operator()(T* ptr) const {
+    ptr->~T();
+    ProtectMemory(ptr, sizeof(T));
+  }
 };
 
 // In general we lack support for arrays. We would need to call the destructor on each element,
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1d31408..a6cf9ea 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1960,8 +1960,8 @@
   // We need to ensure the work line is consistent while performing validation. When we spot a
   // peephole pattern we compute a new line for either the fallthrough instruction or the
   // branch target.
-  ArenaUniquePtr<RegisterLine> branch_line;
-  ArenaUniquePtr<RegisterLine> fallthrough_line;
+  RegisterLineArenaUniquePtr branch_line;
+  RegisterLineArenaUniquePtr fallthrough_line;
 
   switch (inst->Opcode()) {
     case Instruction::NOP:
@@ -4824,7 +4824,7 @@
       AdjustReturnLine(this, ret_inst, target_line);
     }
   } else {
-    ArenaUniquePtr<RegisterLine> copy;
+    RegisterLineArenaUniquePtr copy;
     if (kDebugVerify) {
       copy.reset(RegisterLine::Create(target_line->NumRegs(), this));
       copy->CopyFromLine(target_line);
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index c7d1e6b..b53a45c 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -30,6 +30,7 @@
 #include "handle.h"
 #include "instruction_flags.h"
 #include "method_reference.h"
+#include "register_line.h"
 #include "reg_type_cache.h"
 
 namespace art {
@@ -45,6 +46,7 @@
 class DexPcToReferenceMap;
 class MethodVerifier;
 class RegisterLine;
+using RegisterLineArenaUniquePtr = std::unique_ptr<RegisterLine, RegisterLineArenaDelete>;
 class RegType;
 
 /*
@@ -127,7 +129,7 @@
   }
 
  private:
-  ScopedArenaVector<ArenaUniquePtr<RegisterLine>> register_lines_;
+  ScopedArenaVector<RegisterLineArenaUniquePtr> register_lines_;
 
   DISALLOW_COPY_AND_ASSIGN(PcToRegisterLineTable);
 };
@@ -771,14 +773,14 @@
   PcToRegisterLineTable reg_table_;
 
   // Storage for the register status we're currently working on.
-  ArenaUniquePtr<RegisterLine> work_line_;
+  RegisterLineArenaUniquePtr work_line_;
 
   // The address of the instruction we're currently working on, note that this is in 2 byte
   // quantities
   uint32_t work_insn_idx_;
 
   // Storage for the register status we're saving for later.
-  ArenaUniquePtr<RegisterLine> saved_line_;
+  RegisterLineArenaUniquePtr saved_line_;
 
   const uint32_t dex_method_idx_;  // The method we're working on.
   // Its object representation if known.
diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h
index 330c06a..bfbb78f 100644
--- a/runtime/verifier/register_line-inl.h
+++ b/runtime/verifier/register_line-inl.h
@@ -185,9 +185,12 @@
   }
 }
 
+inline size_t RegisterLine::ComputeSize(size_t num_regs) {
+  return OFFSETOF_MEMBER(RegisterLine, line_) + num_regs * sizeof(uint16_t);
+}
+
 inline RegisterLine* RegisterLine::Create(size_t num_regs, MethodVerifier* verifier) {
-  void* memory = verifier->GetArena().Alloc(OFFSETOF_MEMBER(RegisterLine, line_) +
-                                                (num_regs * sizeof(uint16_t)));
+  void* memory = verifier->GetArena().Alloc(ComputeSize(num_regs));
   return new (memory) RegisterLine(num_regs, verifier);
 }
 
@@ -200,6 +203,12 @@
   SetResultTypeToUnknown(verifier);
 }
 
+inline void RegisterLineArenaDelete::operator()(RegisterLine* ptr) const {
+  const size_t size = ptr != nullptr ? RegisterLine::ComputeSize(ptr->NumRegs()) : 0u;
+  ptr->~RegisterLine();
+  ProtectMemory(ptr, size);
+}
+
 }  // namespace verifier
 }  // namespace art
 
diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h
index b2f5555..d508454 100644
--- a/runtime/verifier/register_line.h
+++ b/runtime/verifier/register_line.h
@@ -197,6 +197,9 @@
     return num_regs_;
   }
 
+  // Return how many bytes of memory a register line uses.
+  ALWAYS_INLINE static size_t ComputeSize(size_t num_regs);
+
   /*
    * Get the "this" pointer from a non-static method invocation. This returns the RegType so the
    * caller can decide whether it needs the reference to be initialized or not. (Can also return
@@ -401,6 +404,13 @@
   DISALLOW_COPY_AND_ASSIGN(RegisterLine);
 };
 
+class RegisterLineArenaDelete : public ArenaDelete<RegisterLine> {
+ public:
+  void operator()(RegisterLine* ptr) const;
+};
+
+
+
 }  // namespace verifier
 }  // namespace art