From: Duncan P. N. Exon Smith Date: Wed, 14 Jan 2015 19:56:10 +0000 (+0000) Subject: IR: Fix a use-after-free in RAUW X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9e4a11f46c4611662d28cec1f2c008ad0ed24023;p=llvm IR: Fix a use-after-free in RAUW Happened pretty commonly during `LLVMContext` teardown when `clang -g` hit an error. This fixes the use-after-free. Next I'll clean up teardown so that it's not RAUW'ing when metadata-tracked values are deleted (only really causes a problem if the graph is mid-construction when teardown starts, but it's still unnecessary work). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226029 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/IR/Metadata.cpp b/lib/IR/Metadata.cpp index ab83252bfda..2c6b332dc8e 100644 --- a/lib/IR/Metadata.cpp +++ b/lib/IR/Metadata.cpp @@ -167,6 +167,11 @@ void ReplaceableMetadataImpl::replaceAllUsesWith(Metadata *MD) { return L.second.second < R.second.second; }); for (const auto &Pair : Uses) { + // Check that this Ref hasn't disappeared after RAUW (when updating a + // previous Ref). + if (!UseMap.count(Pair.first)) + continue; + OwnerTy Owner = Pair.second.first; if (!Owner) { // Update unowned tracking references directly. diff --git a/unittests/IR/MetadataTest.cpp b/unittests/IR/MetadataTest.cpp index 52826d73744..f862f049fcc 100644 --- a/unittests/IR/MetadataTest.cpp +++ b/unittests/IR/MetadataTest.cpp @@ -484,6 +484,34 @@ TEST_F(ValueAsMetadataTest, UpdatesOnRAUW) { EXPECT_TRUE(MD->getValue() == GV1.get()); } +TEST_F(ValueAsMetadataTest, CollidingDoubleUpdates) { + // Create a constant. + ConstantAsMetadata *CI = ConstantAsMetadata::get( + ConstantInt::get(getGlobalContext(), APInt(8, 0))); + + // Create a temporary to prevent nodes from resolving. + std::unique_ptr Temp(MDNode::getTemporary(Context, None)); + + // When the first operand of N1 gets reset to nullptr, it'll collide with N2. + Metadata *Ops1[] = {CI, CI, Temp.get()}; + Metadata *Ops2[] = {nullptr, CI, Temp.get()}; + + auto *N1 = MDTuple::get(Context, Ops1); + auto *N2 = MDTuple::get(Context, Ops2); + ASSERT_NE(N1, N2); + + // Tell metadata that the constant is getting deleted. + // + // After this, N1 will be invalid, so don't touch it. + ValueAsMetadata::handleDeletion(CI->getValue()); + EXPECT_EQ(nullptr, N2->getOperand(0)); + EXPECT_EQ(nullptr, N2->getOperand(1)); + EXPECT_EQ(Temp.get(), N2->getOperand(2)); + + // Clean up Temp for teardown. + Temp->replaceAllUsesWith(nullptr); +} + typedef MetadataTest TrackingMDRefTest; TEST_F(TrackingMDRefTest, UpdatesOnRAUW) {