diff options
-rw-r--r-- | src/mongo/scripting/mozjs/objectwrapper.cpp | 77 |
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*/; |