summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/exec/group.cpp2
-rw-r--r--src/mongo/db/matcher/expression_where.cpp1
-rw-r--r--src/mongo/dbtests/jstests.cpp3
-rw-r--r--src/mongo/scripting/engine.cpp11
-rw-r--r--src/mongo/scripting/engine.h4
-rw-r--r--src/mongo/scripting/mozjs/bson.cpp55
-rw-r--r--src/mongo/scripting/mozjs/bson.h3
-rw-r--r--src/mongo/scripting/mozjs/cursor.cpp4
-rw-r--r--src/mongo/scripting/mozjs/implscope.cpp24
-rw-r--r--src/mongo/scripting/mozjs/implscope.h7
-rw-r--r--src/mongo/scripting/mozjs/jsthread.cpp4
-rw-r--r--src/mongo/scripting/mozjs/mongo.cpp14
-rw-r--r--src/mongo/scripting/mozjs/nativefunction.cpp2
-rw-r--r--src/mongo/scripting/mozjs/objectwrapper.cpp9
-rw-r--r--src/mongo/scripting/mozjs/objectwrapper.h2
-rw-r--r--src/mongo/scripting/mozjs/proxyscope.cpp8
-rw-r--r--src/mongo/scripting/mozjs/proxyscope.h4
-rw-r--r--src/mongo/scripting/mozjs/valuereader.cpp24
-rw-r--r--src/mongo/scripting/mozjs/valuereader.h4
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);