diff options
author | Andrew Morrow <acm@mongodb.com> | 2014-04-08 19:55:32 -0400 |
---|---|---|
committer | Matt Kangas <matt.kangas@mongodb.com> | 2014-04-09 18:54:21 -0400 |
commit | 758f9f60ff799a76d6373de6b8ce820ebbd72bfc (patch) | |
tree | 8d7e67cd942746fdff36044326d48706519bc719 | |
parent | 2af46bcef99628210d00a24edc5bfa37966cd9a4 (diff) | |
download | mongo-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.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; |