diff options
-rw-r--r-- | jstests/core/pop_server_13516.js | 20 | ||||
-rw-r--r-- | src/mongo/bson/mutable/document.cpp | 10 |
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; |