Browse 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 13 years ago
parent
commit
f18114000f
2 changed files with 12 additions and 2 deletions
  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);
 }