Fix the ValueMap copy constructor. The issue is that the map keys are value
authorDuncan Sands <baldrick@free.fr>
Fri, 30 Jul 2010 05:49:32 +0000 (05:49 +0000)
committerDuncan Sands <baldrick@free.fr>
Fri, 30 Jul 2010 05:49:32 +0000 (05:49 +0000)
handles with a pointer to the containing map.  When a map is copied, these
pointers need to be corrected to point to the new map.  If not, then consider
the case of a map M1 which maps a value V to something.  Create a copy M2 of
M1.  At this point there are two value handles on V, one representing V as a
key in M1, the other representing V as a key in M2.  But both value handles
point to M1 as the containing map.  Now delete V.  The value handles remove
themselves from their containing map (which destroys them), but only the first
value handle is successful: the second one cannot remove itself from M1 as
(once the first one has removed itself) there is nothing there to remove; it
is therefore not destroyed.  This causes an assertion failure "All references
to V were not removed?".

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

include/llvm/ADT/ValueMap.h
unittests/ADT/ValueMapTest.cpp

index 98e437732584f1ffac2b5e1dfd55d06ed8dd3721..f7560681097812cc2d1da1fe99cf84039785f01a 100644 (file)
@@ -87,7 +87,12 @@ public:
   typedef ValueT mapped_type;
   typedef std::pair<KeyT, ValueT> value_type;
 
-  ValueMap(const ValueMap& Other) : Map(Other.Map), Data(Other.Data) {}
+  ValueMap(const ValueMap& Other) : Map(Other.Map), Data(Other.Data) {
+    // Each ValueMapCVH key contains a pointer to the containing ValueMap.
+    // The keys in the new map need to point to the new map, not Other.
+    for (typename MapT::iterator I = Map.begin(), E = Map.end(); I != E; ++I)
+      I->first.Map = this;
+  }
 
   explicit ValueMap(unsigned NumInitBuckets = 64)
     : Map(NumInitBuckets), Data() {}
index 152e8eaaf1f1804c16c3489bb7310a3962890f78..ff7c3b55b70ea63cf8da343d678af8ffcccf3e09 100644 (file)
@@ -39,6 +39,15 @@ protected:
 typedef ::testing::Types<Value, Instruction, const Instruction> KeyTypes;
 TYPED_TEST_CASE(ValueMapTest, KeyTypes);
 
+TYPED_TEST(ValueMapTest, CopyConstructor) {
+  ValueMap<TypeParam*, int> VM1;
+  VM1[this->AddV.get()] = 7;
+  ValueMap<TypeParam*, int> VM2(VM1);
+  this->AddV.reset();
+  EXPECT_TRUE(VM1.empty());
+  EXPECT_TRUE(VM2.empty());
+}
+
 TYPED_TEST(ValueMapTest, Null) {
   ValueMap<TypeParam*, int> VM1;
   VM1[NULL] = 7;