IR: Fix memory corruption in MDNode new/delete
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>
Tue, 9 Dec 2014 23:56:39 +0000 (23:56 +0000)
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>
Tue, 9 Dec 2014 23:56:39 +0000 (23:56 +0000)
There were two major problems with `MDNode` memory management.

 1. `MDNode::operator new()` called a placement array constructor for
    `MDOperand`.  What?  Each operand needs to be placed individually.

 2. `MDNode::operator delete()` failed to destruct the `MDOperand`s at
    all.

Frankly it's hard to understand how this worked locally, how this
survived an LTO bootstrap, or how it worked on most of the bots.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@223858 91177308-0d34-0410-b5e6-96231b3b80d8

lib/IR/Metadata.cpp

index 7a354c42c4c221f76501d89a7752d4570bdeafb5..0f748495261bfd0434b8934149289d1e679d1842 100644 (file)
@@ -378,14 +378,18 @@ StringRef MDString::getString() const {
 
 void *MDNode::operator new(size_t Size, unsigned NumOps) {
   void *Ptr = ::operator new(Size + NumOps * sizeof(MDOperand));
-  MDOperand *First = new (Ptr) MDOperand[NumOps];
-  return First + NumOps;
+  MDOperand *O = static_cast<MDOperand *>(Ptr);
+  for (MDOperand *E = O + NumOps; O != E; ++O)
+    (void)new (O) MDOperand;
+  return O;
 }
 
 void MDNode::operator delete(void *Mem) {
   MDNode *N = static_cast<MDNode *>(Mem);
-  MDOperand *Last = static_cast<MDOperand *>(Mem);
-  ::operator delete(Last - N->NumOperands);
+  MDOperand *O = static_cast<MDOperand *>(Mem);
+  for (MDOperand *E = O - N->NumOperands; O != E; --O)
+    (O - 1)->~MDOperand();
+  ::operator delete(O);
 }
 
 MDNode::MDNode(LLVMContext &Context, unsigned ID, ArrayRef<Metadata *> MDs)