Parcourir la source

[1470] Iterate over unchanging map when removing identical elements

A method iterates over a std::map and removes from it elements that
match those in another map.  This can lead to a problem on some
operating systems if the element removal affects the iterator.
The fix here is to iterate over the (unchanging) reference map.
Stephen Morris il y a 13 ans
Parent
commit
f18114000f
2 fichiers modifiés avec 12 ajouts et 2 suppressions
  1. 6 2
      src/lib/cc/data.cc
  2. 6 0
      src/lib/cc/tests/data_unittests.cc

+ 6 - 2
src/lib/cc/data.cc

@@ -843,10 +843,14 @@ removeIdentical(ElementPtr a, ConstElementPtr b) {
         isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
     }
 
-    const std::map<std::string, ConstElementPtr>& m = a->mapValue();
+    // As maps do not allow entries with multiple keys, we can either iterate
+    // over a checking for identical entries in b or vice-versa.  As elements
+    // are removed from a if a match is found, we choose to iterate over b to
+    // avoid problems with element removal affecting the iterator.
+    const std::map<std::string, ConstElementPtr>& m = b->mapValue();
     for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
          it != m.end() ; ++it) {
-        if (b->contains((*it).first)) {
+        if (a->contains((*it).first)) {
             if (a->get((*it).first)->equals(*b->get((*it).first))) {
                 a->remove((*it).first);
             }

+ 6 - 0
src/lib/cc/tests/data_unittests.cc

@@ -523,6 +523,12 @@ TEST(Element, removeIdentical) {
     removeIdentical(a, b);
     EXPECT_EQ(*a, *c);
 
+    a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }");
+    b = Element::fromJSON("{ \"c\": 3, \"b\": 2 }");
+    c = Element::fromJSON("{ \"a\": 1 }");
+    removeIdentical(a, b);
+    EXPECT_EQ(*a, *c);
+
     EXPECT_THROW(removeIdentical(Element::create(1), Element::create(2)), TypeError);
 }