summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Morrow <acm@mongodb.com>2014-04-08 19:55:32 -0400
committerMatt Kangas <matt.kangas@mongodb.com>2014-04-09 18:54:21 -0400
commit758f9f60ff799a76d6373de6b8ce820ebbd72bfc (patch)
tree8d7e67cd942746fdff36044326d48706519bc719
parent2af46bcef99628210d00a24edc5bfa37966cd9a4 (diff)
downloadmongo-758f9f60ff799a76d6373de6b8ce820ebbd72bfc.tar.gz
SERVER-13516 When failing to bulk right copy don't access rep after resolving
(cherry picked from commit e5be760537665a25da2bc632a111859f1b8bbf79)
-rw-r--r--jstests/core/pop_server_13516.js20
-rw-r--r--src/mongo/bson/mutable/document.cpp10
2 files changed, 27 insertions, 3 deletions
diff --git a/jstests/core/pop_server_13516.js b/jstests/core/pop_server_13516.js
new file mode 100644
index 00000000000..231889b7a7d
--- /dev/null
+++ b/jstests/core/pop_server_13516.js
@@ -0,0 +1,20 @@
+// Regression test for SERVER-13516 crash
+
+var t = db.jstests_pop_server_13516;
+t.drop();
+
+var id = NumberInt(0);
+var object = {
+ _id : id,
+ data : []
+};
+
+for (var i = 0; i < 4096; i++) {
+ object.data[i] = 0;
+}
+
+t.insert(object);
+t.update({ _id : id}, { $pop : { data : -1 } });
+
+var modified = t.findOne();
+assert.eq(4095, modified.data.length);
diff --git a/src/mongo/bson/mutable/document.cpp b/src/mongo/bson/mutable/document.cpp
index 5080abf01c4..6ef13e1de43 100644
--- a/src/mongo/bson/mutable/document.cpp
+++ b/src/mongo/bson/mutable/document.cpp
@@ -2137,7 +2137,7 @@ namespace mutablebson {
if (current == Element::kOpaqueRepIdx)
current = const_cast<Impl*>(this)->resolveLeftChild(repIdx);
- // We need write the element, and then walk rightwards.
+ // We need to write the element, and then walk rightwards.
while (current != Element::kInvalidRepIdx) {
writeElement(current, builder);
@@ -2178,8 +2178,12 @@ namespace mutablebson {
break;
}
- // We couldn't bulk copy, and our right sibling is opaque. We need to resolve.
- const_cast<Impl*>(this)->resolveRightSibling(current);
+ // We couldn't bulk copy, and our right sibling is opaque. We need to
+ // resolve. Note that the call to resolve may invalidate 'currentRep', so
+ // rather than falling through and acquiring the index by examining currentRep,
+ // update it with the return value of resolveRightSibling and restart the loop.
+ current = const_cast<Impl*>(this)->resolveRightSibling(current);
+ continue;
}
current = currentRep.sibling.right;