diff options
author | Marko Vojvodic <marko.vojvodic@mongodb.com> | 2016-11-02 15:59:53 -0400 |
---|---|---|
committer | Marko Vojvodic <marko.vojvodic@mongodb.com> | 2016-11-04 15:40:04 -0400 |
commit | c1567abb4ace3e042931ae705d5b3afd8fbd750b (patch) | |
tree | b24dc0ec4e697fac25ad591310f8bd89a22d49e2 | |
parent | a7f147affcc6fe1a751e71a7bff1ad417ddb3b84 (diff) | |
download | mongo-c1567abb4ace3e042931ae705d5b3afd8fbd750b.tar.gz |
SERVER-26462 Check if _buffer is allocated in DocumentStorage::clone()
-rw-r--r-- | jstests/aggregation/bugs/server26462.js | 29 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_value_test.cpp | 8 |
3 files changed, 41 insertions, 2 deletions
diff --git a/jstests/aggregation/bugs/server26462.js b/jstests/aggregation/bugs/server26462.js new file mode 100644 index 00000000000..b0ef33ae35b --- /dev/null +++ b/jstests/aggregation/bugs/server26462.js @@ -0,0 +1,29 @@ +// Tests that adding a field that only contains metadata does not cause a segmentation fault when +// grouping on the added field. +(function() { + "use strict"; + + // Drop the old test collection, if any. + db.server26462.drop(); + + // Insert some test documents into the collection. + assert.writeOK(db.server26462.insert({"_id": 1, "title": "cakes and ale"})); + assert.writeOK(db.server26462.insert({"_id": 2, "title": "more cakes"})); + assert.writeOK(db.server26462.insert({"_id": 3, "title": "bread"})); + assert.writeOK(db.server26462.insert({"_id": 4, "title": "some cakes"})); + + // Create a text index on the documents. + assert.commandWorked(db.server26462.createIndex({title: "text"})); + + // Add a metadata only field in the aggregation pipeline and use that field in the $group _id. + let res = db.server26462 + .aggregate([ + {$match: {$text: {$search: "cake"}}}, + {$addFields: {fooScore: {$meta: "textScore"}}}, + {$group: {_id: "$fooScore", count: {$sum: 1}}} + ]) + .itcount(); + + // Assert that the command worked. + assert.eq(2, res); +})(); diff --git a/src/mongo/db/pipeline/document.cpp b/src/mongo/db/pipeline/document.cpp index 62ac9c1ac32..51fd08d4d20 100644 --- a/src/mongo/db/pipeline/document.cpp +++ b/src/mongo/db/pipeline/document.cpp @@ -186,10 +186,12 @@ intrusive_ptr<DocumentStorage> DocumentStorage::clone() const { // Make a copy of the buffer. // It is very important that the positions of each field are the same after cloning. - const size_t bufferBytes = (_bufferEnd + hashTabBytes()) - _buffer; + const size_t bufferBytes = allocatedBytes(); out->_buffer = new char[bufferBytes]; out->_bufferEnd = out->_buffer + (_bufferEnd - _buffer); - memcpy(out->_buffer, _buffer, bufferBytes); + if (bufferBytes > 0) { + memcpy(out->_buffer, _buffer, bufferBytes); + } // Copy remaining fields out->_usedBytes = _usedBytes; diff --git a/src/mongo/db/pipeline/document_value_test.cpp b/src/mongo/db/pipeline/document_value_test.cpp index adec442f7b8..f8f451bede1 100644 --- a/src/mongo/db/pipeline/document_value_test.cpp +++ b/src/mongo/db/pipeline/document_value_test.cpp @@ -104,6 +104,14 @@ TEST(DocumentConstruction, FromInitializerList) { ASSERT_EQUALS("q", getNthField(document, 1).second.getString()); } +TEST(DocumentConstruction, FromEmptyDocumentClone) { + Document document; + ASSERT_EQUALS(0U, document.size()); + // Prior to SERVER-26462, cloning an empty document would cause a segmentation fault. + Document documentClone = document.clone(); + ASSERT_DOCUMENT_EQ(document, documentClone); +} + /** Add Document fields. */ class AddField { public: |