summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/scripting/mozjs/objectwrapper.cpp77
1 files changed, 43 insertions, 34 deletions
diff --git a/src/mongo/scripting/mozjs/objectwrapper.cpp b/src/mongo/scripting/mozjs/objectwrapper.cpp
index 2f14816a7f9..eb15dacccc6 100644
--- a/src/mongo/scripting/mozjs/objectwrapper.cpp
+++ b/src/mongo/scripting/mozjs/objectwrapper.cpp
@@ -467,51 +467,60 @@ BSONObj ObjectWrapper::toBSON() {
// emplace() inside ValueWriter. The runtime asserts enabled by MozJS's
// debug mode will catch runtime errors, but be aware of how difficult this
// is to get right and what to look for if one of them bites you.
- WriteFieldRecursionFrames frames;
- frames.emplace(_context, _object, nullptr, StringData{});
BSONObjBuilder b;
- // We special case the _id field in top-level objects and move it to the front.
- // This matches other drivers behavior and makes finding the _id field quicker in BSON.
- if (hasOwnField(InternedString::_id)) {
- _writeField(&b, InternedString::_id, &frames, frames.top().originalBSON);
- }
+ {
+ // NOTE: Keep the frames in a scope so that it is clear that
+ // we always destroy them before we destroy 'b'. It is
+ // important to do so: if 'b' is destroyed before the frames,
+ // and we don't pop all of the frames (say, due to an
+ // exeption), then the frame dtors would write to freed
+ // memory.
+ WriteFieldRecursionFrames frames;
+ frames.emplace(_context, _object, nullptr, StringData{});
+
+ // We special case the _id field in top-level objects and move it to the front.
+ // This matches other drivers behavior and makes finding the _id field quicker in BSON.
+ if (hasOwnField(InternedString::_id)) {
+ _writeField(&b, InternedString::_id, &frames, frames.top().originalBSON);
+ }
- while (frames.size()) {
- auto& frame = frames.top();
+ while (frames.size()) {
+ auto& frame = frames.top();
- // If the index is the same as length, we've seen all the keys at this
- // level and should go up a level
- if (frame.idx == frame.ids.length()) {
- frames.pop();
- continue;
- }
+ // If the index is the same as length, we've seen all the keys at this
+ // level and should go up a level
+ if (frame.idx == frame.ids.length()) {
+ frames.pop();
+ continue;
+ }
- if (frame.idx == 0 && frame.originalBSON && !frame.altered) {
- // If this is our first look at the object and it has an unaltered
- // bson behind it, move idx to the end so we'll roll up on the next
- // pass through the loop.
- frame.subbob_or(&b)->appendElements(*frame.originalBSON);
- frame.idx = frame.ids.length();
- continue;
- }
+ if (frame.idx == 0 && frame.originalBSON && !frame.altered) {
+ // If this is our first look at the object and it has an unaltered
+ // bson behind it, move idx to the end so we'll roll up on the next
+ // pass through the loop.
+ frame.subbob_or(&b)->appendElements(*frame.originalBSON);
+ frame.idx = frame.ids.length();
+ continue;
+ }
- id.set(frame.ids[frame.idx++]);
+ id.set(frame.ids[frame.idx++]);
- if (frames.size() == 1) {
- IdWrapper idw(_context, id);
+ if (frames.size() == 1) {
+ IdWrapper idw(_context, id);
- // TODO: check if it's cheaper to just compare with an interned
- // string of "_id" rather than with ascii
- if (idw.isString() && idw.equalsAscii("_id")) {
- continue;
+ // TODO: check if it's cheaper to just compare with an interned
+ // string of "_id" rather than with ascii
+ if (idw.isString() && idw.equalsAscii("_id")) {
+ continue;
+ }
}
- }
- // writeField invokes ValueWriter with the frame stack, which will push
- // onto frames for subobjects, which will effectively recurse the loop.
- _writeField(frame.subbob_or(&b), JS::HandleId(id), &frames, frame.originalBSON);
+ // writeField invokes ValueWriter with the frame stack, which will push
+ // onto frames for subobjects, which will effectively recurse the loop.
+ _writeField(frame.subbob_or(&b), JS::HandleId(id), &frames, frame.originalBSON);
+ }
}
const int sizeWithEOO = b.len() + 1 /*EOO*/ - 4 /*BSONObj::Holder ref count*/;