diff options
-rw-r--r-- | src/mongo/db/exec/group.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_where.cpp | 1 | ||||
-rw-r--r-- | src/mongo/dbtests/jstests.cpp | 3 | ||||
-rw-r--r-- | src/mongo/scripting/engine.cpp | 11 | ||||
-rw-r--r-- | src/mongo/scripting/engine.h | 4 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/bson.cpp | 55 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/bson.h | 3 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/cursor.cpp | 4 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/implscope.cpp | 24 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/implscope.h | 7 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/jsthread.cpp | 4 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/mongo.cpp | 14 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/nativefunction.cpp | 2 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/objectwrapper.cpp | 9 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/objectwrapper.h | 2 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/proxyscope.cpp | 8 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/proxyscope.h | 4 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/valuereader.cpp | 24 | ||||
-rw-r--r-- | src/mongo/scripting/mozjs/valuereader.h | 4 |
19 files changed, 127 insertions, 58 deletions
diff --git a/src/mongo/db/exec/group.cpp b/src/mongo/db/exec/group.cpp index ca6be17be55..43b8bf7ec6c 100644 --- a/src/mongo/db/exec/group.cpp +++ b/src/mongo/db/exec/group.cpp @@ -137,6 +137,8 @@ Status GroupStage::processObject(const BSONObj& obj) { return getKeyStatus; } + _scope->advanceGeneration(); + int& n = _groupMap[key]; if (n == 0) { n = _groupMap.size(); diff --git a/src/mongo/db/matcher/expression_where.cpp b/src/mongo/db/matcher/expression_where.cpp index 21c276a10b6..8f26ad7ca1e 100644 --- a/src/mongo/db/matcher/expression_where.cpp +++ b/src/mongo/db/matcher/expression_where.cpp @@ -135,6 +135,7 @@ bool WhereMatchExpression::matches(const MatchableDocument* doc, MatchDetails* d _scope->init(&_userScope); } + _scope->advanceGeneration(); _scope->setObject("obj", const_cast<BSONObj&>(obj)); _scope->setBoolean("fullObject", true); // this is a hack b/c fullObject used to be relevant diff --git a/src/mongo/dbtests/jstests.cpp b/src/mongo/dbtests/jstests.cpp index 5d21645f3f7..aac958bda4f 100644 --- a/src/mongo/dbtests/jstests.cpp +++ b/src/mongo/dbtests/jstests.cpp @@ -118,7 +118,8 @@ public: s->setNumber("notANumberVal", std::numeric_limits<double>::quiet_NaN()); ASSERT(!s->getBoolean("notANumberVal")); - s->setElement("nullVal", BSONObjBuilder().appendNull("null").obj().getField("null")); + auto obj = BSONObjBuilder().appendNull("null").obj(); + s->setElement("nullVal", obj.getField("null"), obj); ASSERT(!s->getBoolean("nullVal")); s->setNumber("zeroVal", 0); diff --git a/src/mongo/scripting/engine.cpp b/src/mongo/scripting/engine.cpp index 27daa08b134..632957a5d08 100644 --- a/src/mongo/scripting/engine.cpp +++ b/src/mongo/scripting/engine.cpp @@ -219,7 +219,7 @@ void Scope::loadStored(OperationContext* txn, bool ignoreNotConnected) { set<string> thisTime; while (c->more()) { - BSONObj o = c->nextSafe(); + BSONObj o = c->nextSafe().getOwned(); BSONElement n = o["_id"]; BSONElement v = o["value"]; @@ -227,7 +227,7 @@ void Scope::loadStored(OperationContext* txn, bool ignoreNotConnected) { uassert(10210, "value has to be set", v.type() != EOO); try { - setElement(n.valuestr(), v); + setElement(n.valuestr(), v, o); thisTime.insert(n.valuestr()); _storedNames.insert(n.valuestr()); } catch (const DBException& setElemEx) { @@ -417,6 +417,9 @@ public: void gc() { _real->gc(); } + void advanceGeneration() { + _real->advanceGeneration(); + } bool isKillPending() const { return _real->isKillPending(); } @@ -453,8 +456,8 @@ public: void setString(const char* field, StringData val) { _real->setString(field, val); } - void setElement(const char* field, const BSONElement& val) { - _real->setElement(field, val); + void setElement(const char* field, const BSONElement& val, const BSONObj& parent) { + _real->setElement(field, val, parent); } void setObject(const char* field, const BSONObj& obj, bool readOnly = true) { _real->setObject(field, obj, readOnly); diff --git a/src/mongo/scripting/engine.h b/src/mongo/scripting/engine.h index 8f096dce725..07dc3d24ce7 100644 --- a/src/mongo/scripting/engine.h +++ b/src/mongo/scripting/engine.h @@ -82,7 +82,7 @@ public: } virtual Decimal128 getNumberDecimal(const char* field) = 0; - virtual void setElement(const char* field, const BSONElement& e) = 0; + virtual void setElement(const char* field, const BSONElement& e, const BSONObj& parent) = 0; virtual void setNumber(const char* field, double val) = 0; virtual void setString(const char* field, StringData val) = 0; virtual void setObject(const char* field, const BSONObj& obj, bool readOnly = true) = 0; @@ -103,6 +103,8 @@ public: virtual void gc() = 0; + virtual void advanceGeneration() = 0; + virtual ScriptingFunction createFunction(const char* code); /** diff --git a/src/mongo/scripting/mozjs/bson.cpp b/src/mongo/scripting/mozjs/bson.cpp index 2dd1d717dc3..8155e083e9c 100644 --- a/src/mongo/scripting/mozjs/bson.cpp +++ b/src/mongo/scripting/mozjs/bson.cpp @@ -30,6 +30,7 @@ #include "mongo/scripting/mozjs/bson.h" +#include <boost/optional.hpp> #include <set> #include "mongo/scripting/mozjs/idwrapper.h" @@ -56,31 +57,59 @@ namespace { * the appearance of mutable state on the read/write versions. */ struct BSONHolder { - BSONHolder(const BSONObj& obj, bool ro) - : _obj(obj.getOwned()), _resolved(false), _readOnly(ro), _altered(false) {} + BSONHolder(const BSONObj& obj, const BSONObj* parent, std::size_t generation, bool ro) + : _obj(obj), + _generation(generation), + _isOwned(obj.isOwned() || (parent && parent->isOwned())), + _resolved(false), + _readOnly(ro), + _altered(false) { + if (parent) { + _parent.emplace(*parent); + } + } + + const BSONObj& getOwner() const { + return _parent ? *(_parent) : _obj; + } + + void uassertValid(JSContext* cx) const { + if (!_isOwned && getScope(cx)->getGeneration() != _generation) + uasserted(ErrorCodes::BadValue, + "Attempt to access an invalidated BSON Object in JS scope"); + } BSONObj _obj; + boost::optional<BSONObj> _parent; + std::size_t _generation; + bool _isOwned; bool _resolved; bool _readOnly; bool _altered; std::set<std::string> _removed; }; -BSONHolder* getHolder(JSObject* obj) { - return static_cast<BSONHolder*>(JS_GetPrivate(obj)); +BSONHolder* getValidHolder(JSContext* cx, JSObject* obj) { + auto holder = static_cast<BSONHolder*>(JS_GetPrivate(obj)); + + if (holder) + holder->uassertValid(cx); + + return holder; } } // namespace -void BSONInfo::make(JSContext* cx, JS::MutableHandleObject obj, BSONObj bson, bool ro) { +void BSONInfo::make( + JSContext* cx, JS::MutableHandleObject obj, BSONObj bson, const BSONObj* parent, bool ro) { auto scope = getScope(cx); scope->getProto<BSONInfo>().newObject(obj); - JS_SetPrivate(obj, new BSONHolder(bson, ro)); + JS_SetPrivate(obj, new BSONHolder(bson, parent, scope->getGeneration(), ro)); } void BSONInfo::finalize(JSFreeOp* fop, JSObject* obj) { - auto holder = getHolder(obj); + auto holder = static_cast<BSONHolder*>(JS_GetPrivate(obj)); if (!holder) return; @@ -89,7 +118,7 @@ void BSONInfo::finalize(JSFreeOp* fop, JSObject* obj) { } void BSONInfo::enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& properties) { - auto holder = getHolder(obj); + auto holder = getValidHolder(cx, obj); if (!holder) return; @@ -119,7 +148,7 @@ void BSONInfo::enumerate(JSContext* cx, JS::HandleObject obj, JS::AutoIdVector& void BSONInfo::setProperty( JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool strict, JS::MutableHandleValue vp) { - auto holder = getHolder(obj); + auto holder = getValidHolder(cx, obj); if (holder) { if (holder->_readOnly) { @@ -139,7 +168,7 @@ void BSONInfo::setProperty( } void BSONInfo::delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* succeeded) { - auto holder = getHolder(obj); + auto holder = getValidHolder(cx, obj); if (holder) { if (holder->_readOnly) { @@ -155,7 +184,7 @@ void BSONInfo::delProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, } void BSONInfo::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp) { - auto holder = getHolder(obj); + auto holder = getValidHolder(cx, obj); *resolvedp = false; @@ -178,7 +207,7 @@ void BSONInfo::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, boo JS::RootedValue vp(cx); - ValueReader(cx, &vp).fromBSONElement(elem, holder->_readOnly); + ValueReader(cx, &vp).fromBSONElement(elem, holder->getOwner(), holder->_readOnly); o.defineProperty(id, vp, JSPROP_ENUMERATE); @@ -196,7 +225,7 @@ void BSONInfo::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, boo std::tuple<BSONObj*, bool> BSONInfo::originalBSON(JSContext* cx, JS::HandleObject obj) { std::tuple<BSONObj*, bool> out(nullptr, false); - if (auto holder = getHolder(obj)) + if (auto holder = getValidHolder(cx, obj)) out = std::make_tuple(&holder->_obj, holder->_altered); return out; diff --git a/src/mongo/scripting/mozjs/bson.h b/src/mongo/scripting/mozjs/bson.h index 82e1e5d0cdb..d341f0a856b 100644 --- a/src/mongo/scripting/mozjs/bson.h +++ b/src/mongo/scripting/mozjs/bson.h @@ -69,7 +69,8 @@ struct BSONInfo : public BaseInfo { static const JSFunctionSpec freeFunctions[2]; static std::tuple<BSONObj*, bool> originalBSON(JSContext* cx, JS::HandleObject obj); - static void make(JSContext* cx, JS::MutableHandleObject obj, BSONObj bson, bool ro); + static void make( + JSContext* cx, JS::MutableHandleObject obj, BSONObj bson, const BSONObj* parent, bool ro); }; } // namespace mozjs diff --git a/src/mongo/scripting/mozjs/cursor.cpp b/src/mongo/scripting/mozjs/cursor.cpp index 79c1f5cf749..072e2ffb999 100644 --- a/src/mongo/scripting/mozjs/cursor.cpp +++ b/src/mongo/scripting/mozjs/cursor.cpp @@ -83,7 +83,9 @@ void CursorInfo::Functions::next::call(JSContext* cx, JS::CallArgs args) { BSONObj bson = cursor->next(); bool ro = o.hasField("_ro") ? o.getBoolean("_ro") : false; - ValueReader(cx, args.rval()).fromBSON(bson, ro); + // getOwned because cursor->next() gives us unowned bson from an internal + // buffer and we need to make a copy + ValueReader(cx, args.rval()).fromBSON(bson.getOwned(), nullptr, ro); } void CursorInfo::Functions::hasNext::call(JSContext* cx, JS::CallArgs args) { diff --git a/src/mongo/scripting/mozjs/implscope.cpp b/src/mongo/scripting/mozjs/implscope.cpp index 2ca8e4d33ce..debb02f968b 100644 --- a/src/mongo/scripting/mozjs/implscope.cpp +++ b/src/mongo/scripting/mozjs/implscope.cpp @@ -249,6 +249,7 @@ MozJSImplScope::MozJSImplScope(MozJSScriptEngine* engine) _connectState(ConnectState::Not), _status(Status::OK()), _quickExit(false), + _generation(0), _binDataProto(_context), _bsonProto(_context), _countDownLatchProto(_context), @@ -327,7 +328,7 @@ void MozJSImplScope::init(const BSONObj* data) { BSONObjIterator i(*data); while (i.more()) { BSONElement e = i.next(); - setElement(e.fieldName(), e); + setElement(e.fieldName(), e, *data); } } @@ -349,10 +350,10 @@ void MozJSImplScope::setBoolean(const char* field, bool val) { ObjectWrapper(_context, _global).setBoolean(field, val); } -void MozJSImplScope::setElement(const char* field, const BSONElement& e) { +void MozJSImplScope::setElement(const char* field, const BSONElement& e, const BSONObj& parent) { MozJSEntry entry(this); - ObjectWrapper(_context, _global).setBSONElement(field, e, false); + ObjectWrapper(_context, _global).setBSONElement(field, e, parent, false); } void MozJSImplScope::setObject(const char* field, const BSONObj& obj, bool readOnly) { @@ -423,7 +424,7 @@ BSONObj MozJSImplScope::callThreadArgs(const BSONObj& args) { MozJSEntry entry(this); JS::RootedValue function(_context); - ValueReader(_context, &function).fromBSONElement(args.firstElement(), true); + ValueReader(_context, &function).fromBSONElement(args.firstElement(), args, true); int argc = args.nFields() - 1; @@ -433,7 +434,7 @@ BSONObj MozJSImplScope::callThreadArgs(const BSONObj& args) { JS::RootedValue value(_context); for (int i = 0; i < argc; ++i) { - ValueReader(_context, &value).fromBSONElement(*it, true); + ValueReader(_context, &value).fromBSONElement(*it, args, true); argv.append(value); it.next(); } @@ -521,7 +522,7 @@ int MozJSImplScope::invoke(ScriptingFunction func, BSONElement next = it.next(); JS::RootedValue value(_context); - ValueReader(_context, &value).fromBSONElement(next, readOnlyArgs); + ValueReader(_context, &value).fromBSONElement(next, *argsObject, readOnlyArgs); args.append(value); } @@ -529,7 +530,7 @@ int MozJSImplScope::invoke(ScriptingFunction func, JS::RootedValue smrecv(_context); if (recv) - ValueReader(_context, &smrecv).fromBSON(*recv, readOnlyRecv); + ValueReader(_context, &smrecv).fromBSON(*recv, nullptr, readOnlyRecv); else smrecv.setObjectOrNull(_global); @@ -683,6 +684,7 @@ void MozJSImplScope::reset() { unregisterOperation(); _pendingKill.store(false); _pendingGC.store(false); + advanceGeneration(); } void MozJSImplScope::installBSONTypes() { @@ -792,6 +794,14 @@ void MozJSImplScope::setParentStack(std::string parentStack) { _parentStack = std::move(parentStack); } +std::size_t MozJSImplScope::getGeneration() const { + return _generation; +} + +void MozJSImplScope::advanceGeneration() { + _generation++; +} + const std::string& MozJSImplScope::getParentStack() const { return _parentStack; } diff --git a/src/mongo/scripting/mozjs/implscope.h b/src/mongo/scripting/mozjs/implscope.h index 87907ed1984..1222ed38a24 100644 --- a/src/mongo/scripting/mozjs/implscope.h +++ b/src/mongo/scripting/mozjs/implscope.h @@ -117,7 +117,7 @@ public: void setNumber(const char* field, double val) override; void setString(const char* field, StringData val) override; void setBoolean(const char* field, bool val) override; - void setElement(const char* field, const BSONElement& e) override; + void setElement(const char* field, const BSONElement& e, const BSONObj& parent) override; void setObject(const char* field, const BSONObj& obj, bool readOnly) override; void setFunction(const char* field, const char* code) override; @@ -292,6 +292,10 @@ public: void setParentStack(std::string); const std::string& getParentStack() const; + std::size_t getGeneration() const; + + void advanceGeneration() override; + private: void _MozJSCreateFunction(const char* raw, ScriptingFunction functionNumber, @@ -354,6 +358,7 @@ private: int _exitCode; bool _quickExit; std::string _parentStack; + std::size_t _generation; WrapType<BinDataInfo> _binDataProto; WrapType<BSONInfo> _bsonProto; diff --git a/src/mongo/scripting/mozjs/jsthread.cpp b/src/mongo/scripting/mozjs/jsthread.cpp index ff254b1ccf1..35dd5537b5b 100644 --- a/src/mongo/scripting/mozjs/jsthread.cpp +++ b/src/mongo/scripting/mozjs/jsthread.cpp @@ -277,8 +277,8 @@ void JSThreadInfo::Functions::hasFailed::call(JSContext* cx, JS::CallArgs args) } void JSThreadInfo::Functions::returnData::call(JSContext* cx, JS::CallArgs args) { - ValueReader(cx, args.rval()) - .fromBSONElement(getConfig(cx, args)->returnData().firstElement(), true); + auto obj = getConfig(cx, args)->returnData(); + ValueReader(cx, args.rval()).fromBSONElement(obj.firstElement(), obj, true); } void JSThreadInfo::Functions::_threadInject::call(JSContext* cx, JS::CallArgs args) { diff --git a/src/mongo/scripting/mozjs/mongo.cpp b/src/mongo/scripting/mozjs/mongo.cpp index bf99381de36..684870aa5af 100644 --- a/src/mongo/scripting/mozjs/mongo.cpp +++ b/src/mongo/scripting/mozjs/mongo.cpp @@ -137,7 +137,9 @@ void MongoBase::Functions::runCommand::call(JSContext* cx, JS::CallArgs args) { conn->runCommand(database, cmdObj, cmdRes, queryOptions); // the returned object is not read only as some of our tests depend on modifying it. - ValueReader(cx, args.rval()).fromBSON(cmdRes, false /* read only */); + // + // Also, we make a copy here because we want a copy after we dump cmdRes + ValueReader(cx, args.rval()).fromBSON(cmdRes.getOwned(), nullptr, false /* read only */); } void MongoBase::Functions::runCommandWithMetadata::call(JSContext* cx, JS::CallArgs args) { @@ -173,7 +175,7 @@ void MongoBase::Functions::runCommandWithMetadata::call(JSContext* cx, JS::CallA mergedResultBob.append("metadata", res->getMetadata()); auto mergedResult = mergedResultBob.done(); - ValueReader(cx, args.rval()).fromBSON(mergedResult, false); + ValueReader(cx, args.rval()).fromBSON(mergedResult, nullptr, false); } void MongoBase::Functions::find::call(JSContext* cx, JS::CallArgs args) { @@ -385,7 +387,9 @@ void MongoBase::Functions::logout::call(JSContext* cx, JS::CallArgs args) { conn->logout(db, ret); } - ValueReader(cx, args.rval()).fromBSON(ret, false); + // Make a copy because I want to insulate us from whether conn->logout + // writes an owned bson or not + ValueReader(cx, args.rval()).fromBSON(ret.getOwned(), nullptr, false); } void MongoBase::Functions::cursorFromId::call(JSContext* cx, JS::CallArgs args) { @@ -508,7 +512,7 @@ void MongoBase::Functions::copyDatabaseWithSCRAM::call(JSContext* cx, JS::CallAr if (code == ErrorCodes::OK) code = ErrorCodes::UnknownError; - ValueReader(cx, args.rval()).fromBSON(inputObj, true); + ValueReader(cx, args.rval()).fromBSON(inputObj, nullptr, true); return; } @@ -520,7 +524,7 @@ void MongoBase::Functions::copyDatabaseWithSCRAM::call(JSContext* cx, JS::CallAr uasserted(ErrorCodes::InternalError, "copydb client finished before server."); } - ValueReader(cx, args.rval()).fromBSON(inputObj, true); + ValueReader(cx, args.rval()).fromBSON(inputObj, nullptr, true); } void MongoBase::Functions::getClientRPCProtocols::call(JSContext* cx, JS::CallArgs args) { diff --git a/src/mongo/scripting/mozjs/nativefunction.cpp b/src/mongo/scripting/mozjs/nativefunction.cpp index 4d019a5b347..6399bb60709 100644 --- a/src/mongo/scripting/mozjs/nativefunction.cpp +++ b/src/mongo/scripting/mozjs/nativefunction.cpp @@ -92,7 +92,7 @@ void NativeFunctionInfo::call(JSContext* cx, JS::CallArgs args) { BSONObj out = holder->_func(wobj.toBSON(), holder->_ctx); - ValueReader(cx, args.rval()).fromBSONElement(out.firstElement(), false); + ValueReader(cx, args.rval()).fromBSONElement(out.firstElement(), out, false); } void NativeFunctionInfo::finalize(JSFreeOp* fop, JSObject* obj) { diff --git a/src/mongo/scripting/mozjs/objectwrapper.cpp b/src/mongo/scripting/mozjs/objectwrapper.cpp index 2213ec2a029..014c668e9c7 100644 --- a/src/mongo/scripting/mozjs/objectwrapper.cpp +++ b/src/mongo/scripting/mozjs/objectwrapper.cpp @@ -257,16 +257,19 @@ void ObjectWrapper::setBoolean(Key key, bool val) { setValue(key, jsValue); } -void ObjectWrapper::setBSONElement(Key key, const BSONElement& elem, bool readOnly) { +void ObjectWrapper::setBSONElement(Key key, + const BSONElement& elem, + const BSONObj& parent, + bool readOnly) { JS::RootedValue value(_context); - ValueReader(_context, &value).fromBSONElement(elem, readOnly); + ValueReader(_context, &value).fromBSONElement(elem, parent, readOnly); setValue(key, value); } void ObjectWrapper::setBSON(Key key, const BSONObj& obj, bool readOnly) { JS::RootedValue value(_context); - ValueReader(_context, &value).fromBSON(obj, readOnly); + ValueReader(_context, &value).fromBSON(obj, nullptr, readOnly); setValue(key, value); } diff --git a/src/mongo/scripting/mozjs/objectwrapper.h b/src/mongo/scripting/mozjs/objectwrapper.h index 3134083f243..44f1d1ff71e 100644 --- a/src/mongo/scripting/mozjs/objectwrapper.h +++ b/src/mongo/scripting/mozjs/objectwrapper.h @@ -106,7 +106,7 @@ public: void setNumber(Key key, double val); void setString(Key key, StringData val); void setBoolean(Key key, bool val); - void setBSONElement(Key key, const BSONElement& elem, bool readOnly); + void setBSONElement(Key key, const BSONElement& elem, const BSONObj& obj, bool readOnly); void setBSON(Key key, const BSONObj& obj, bool readOnly); void setValue(Key key, JS::HandleValue value); void setObject(Key key, JS::HandleObject value); diff --git a/src/mongo/scripting/mozjs/proxyscope.cpp b/src/mongo/scripting/mozjs/proxyscope.cpp index c97e675f79b..bf49709e495 100644 --- a/src/mongo/scripting/mozjs/proxyscope.cpp +++ b/src/mongo/scripting/mozjs/proxyscope.cpp @@ -119,6 +119,10 @@ void MozJSProxyScope::gc() { _implScope->gc(); } +void MozJSProxyScope::advanceGeneration() { + runOnImplThread([&] { _implScope->advanceGeneration(); }); +} + double MozJSProxyScope::getNumber(const char* field) { double out; runOnImplThread([&] { out = _implScope->getNumber(field); }); @@ -173,8 +177,8 @@ void MozJSProxyScope::setBoolean(const char* field, bool val) { runOnImplThread([&] { _implScope->setBoolean(field, val); }); } -void MozJSProxyScope::setElement(const char* field, const BSONElement& e) { - runOnImplThread([&] { _implScope->setElement(field, e); }); +void MozJSProxyScope::setElement(const char* field, const BSONElement& e, const BSONObj& parent) { + runOnImplThread([&] { _implScope->setElement(field, e, parent); }); } void MozJSProxyScope::setObject(const char* field, const BSONObj& obj, bool readOnly) { diff --git a/src/mongo/scripting/mozjs/proxyscope.h b/src/mongo/scripting/mozjs/proxyscope.h index de932fe35a8..bb9ad41e3e6 100644 --- a/src/mongo/scripting/mozjs/proxyscope.h +++ b/src/mongo/scripting/mozjs/proxyscope.h @@ -127,6 +127,8 @@ public: void gc() override; + void advanceGeneration() override; + double getNumber(const char* field) override; int getNumberInt(const char* field) override; long long getNumberLongLong(const char* field) override; @@ -138,7 +140,7 @@ public: void setNumber(const char* field, double val) override; void setString(const char* field, StringData val) override; void setBoolean(const char* field, bool val) override; - void setElement(const char* field, const BSONElement& e) override; + void setElement(const char* field, const BSONElement& e, const BSONObj& parent) override; void setObject(const char* field, const BSONObj& obj, bool readOnly) override; void setFunction(const char* field, const char* code) override; diff --git a/src/mongo/scripting/mozjs/valuereader.cpp b/src/mongo/scripting/mozjs/valuereader.cpp index 6a0b9dc6fe1..71be53c6ff2 100644 --- a/src/mongo/scripting/mozjs/valuereader.cpp +++ b/src/mongo/scripting/mozjs/valuereader.cpp @@ -48,7 +48,7 @@ namespace mozjs { ValueReader::ValueReader(JSContext* cx, JS::MutableHandleValue value) : _context(cx), _value(value) {} -void ValueReader::fromBSONElement(const BSONElement& elem, bool readOnly) { +void ValueReader::fromBSONElement(const BSONElement& elem, const BSONObj& parent, bool readOnly) { auto scope = getScope(_context); switch (elem.type()) { @@ -92,14 +92,14 @@ void ValueReader::fromBSONElement(const BSONElement& elem, bool readOnly) { sprintf(str, "%i", i++); JS::RootedValue member(_context); - ValueReader(_context, &member).fromBSONElement(subElem, readOnly); + ValueReader(_context, &member).fromBSONElement(subElem, parent, readOnly); ObjectWrapper(_context, array).setValue(str, member); } _value.setObjectOrNull(array); return; } case mongo::Object: - fromBSON(elem.embeddedObject(), readOnly); + fromBSON(elem.embeddedObject(), &parent, readOnly); return; case mongo::Date: _value.setObjectOrNull( @@ -213,7 +213,7 @@ void ValueReader::fromBSONElement(const BSONElement& elem, bool readOnly) { _value.setUndefined(); } -void ValueReader::fromBSON(const BSONObj& obj, bool readOnly) { +void ValueReader::fromBSON(const BSONObj& obj, const BSONObj* parent, bool readOnly) { if (obj.firstElementType() == String && str::equals(obj.firstElementFieldName(), "$ref")) { BSONObjIterator it(obj); const BSONElement ref = it.next(); @@ -222,30 +222,30 @@ void ValueReader::fromBSON(const BSONObj& obj, bool readOnly) { if (id.ok() && str::equals(id.fieldName(), "$id")) { JS::AutoValueArray<2> args(_context); - ValueReader(_context, args[0]).fromBSONElement(ref, readOnly); + ValueReader(_context, args[0]).fromBSONElement(ref, parent ? *parent : obj, readOnly); // id can be a subobject - ValueReader(_context, args[1]).fromBSONElement(id, readOnly); + ValueReader(_context, args[1]).fromBSONElement(id, parent ? *parent : obj, readOnly); - JS::RootedObject obj(_context); + JS::RootedObject robj(_context); auto scope = getScope(_context); - scope->getProto<DBRefInfo>().newInstance(args, &obj); - ObjectWrapper o(_context, obj); + scope->getProto<DBRefInfo>().newInstance(args, &robj); + ObjectWrapper o(_context, robj); while (it.more()) { BSONElement elem = it.next(); - o.setBSONElement(elem.fieldName(), elem, readOnly); + o.setBSONElement(elem.fieldName(), elem, parent ? *parent : obj, readOnly); } - _value.setObjectOrNull(obj); + _value.setObjectOrNull(robj); return; } } JS::RootedObject child(_context); - BSONInfo::make(_context, &child, obj, readOnly); + BSONInfo::make(_context, &child, obj, parent, readOnly); _value.setObjectOrNull(child); } diff --git a/src/mongo/scripting/mozjs/valuereader.h b/src/mongo/scripting/mozjs/valuereader.h index 223600aa5e4..f67b313b628 100644 --- a/src/mongo/scripting/mozjs/valuereader.h +++ b/src/mongo/scripting/mozjs/valuereader.h @@ -47,8 +47,8 @@ public: */ ValueReader(JSContext* cx, JS::MutableHandleValue value); - void fromBSONElement(const BSONElement& elem, bool readOnly); - void fromBSON(const BSONObj& obj, bool readOnly); + void fromBSONElement(const BSONElement& elem, const BSONObj& parent, bool readOnly); + void fromBSON(const BSONObj& obj, const BSONObj* parent, bool readOnly); void fromStringData(StringData sd); void fromDecimal128(Decimal128 decimal); |