summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Vojvodic <marko.vojvodic@mongodb.com>2016-11-02 15:59:53 -0400
committerMarko Vojvodic <marko.vojvodic@mongodb.com>2016-11-04 15:40:04 -0400
commitc1567abb4ace3e042931ae705d5b3afd8fbd750b (patch)
treeb24dc0ec4e697fac25ad591310f8bd89a22d49e2
parenta7f147affcc6fe1a751e71a7bff1ad417ddb3b84 (diff)
downloadmongo-c1567abb4ace3e042931ae705d5b3afd8fbd750b.tar.gz
SERVER-26462 Check if _buffer is allocated in DocumentStorage::clone()
-rw-r--r--jstests/aggregation/bugs/server26462.js29
-rw-r--r--src/mongo/db/pipeline/document.cpp6
-rw-r--r--src/mongo/db/pipeline/document_value_test.cpp8
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: