History

Fixed incorrect Script.require behavior

Karol Suprynowicz committed 3 years ago

Commit 209f1d51 parent 1f2a9871 file · +68 −0Browse files

Showing the changes to libraries/script-engine/src/v8/ScriptEngineV8.cpp (1 of 1 file). Show all

Unified · Split

libraries/script-engine/src/v8/ScriptEngineV8.cpp+68−0
@@ -625,6 +625,9 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 624 unmodified lines
625625 qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName);
626626 #endif
627627 {
628+ ScriptContextV8Wrapper scriptContext(this, getContext(), currentContext()->parentContext());
629+ ScriptContextGuard scriptContextGuard(&scriptContext);
630+
628631 v8::TryCatch tryCatch(getIsolate());
629632 // Since V8 cannot use arbitrary object as global object, objects from main global need to be copied to closure's global object
630633 auto globalObjectContents = _globalObjectContents.Get(_v8Isolate);
@@ -649,12 +652,77 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 18 unmodified lines
649652 // "Script" API is context-dependent, so it needs to be recreated for each new context
650653 registerGlobalObject("Script", new ScriptManagerScriptingInterface(_manager), ScriptEngine::ScriptOwnership);
651654
655+ // Script.require properties need to be copied, since that's where the Script.require cache is
656+ // Get source and destination Script.require objects
657+ try {
658+ v8::Local<v8::Value> oldScriptObjectValue;
659+ if (!globalObjectContents
660+ ->Get(closureContext, v8::String::NewFromUtf8(_v8Isolate, "Script").ToLocalChecked())
661+ .ToLocal(&oldScriptObjectValue)) {
662+ throw(QString("evaluateInClosure: Script API object does not exist in calling script"));
663+ }
664+ if (!oldScriptObjectValue->IsObject()) {
665+ throw(QString("evaluateInClosure: Script API object invalid in calling script"));
666+ }
667+ v8::Local<v8::Object> oldScriptObject = v8::Local<v8::Object>::Cast(oldScriptObjectValue);
668+
669+ v8::Local<v8::Value> oldRequireObjectValue;
670+ if (!oldScriptObject->Get(closureContext, v8::String::NewFromUtf8(_v8Isolate, "require").ToLocalChecked())
671+ .ToLocal(&oldRequireObjectValue)) {
672+ throw(QString("evaluateInClosure: Script.require API object does not exist in calling script"));
673+ }
674+ if (!oldRequireObjectValue->IsObject()) {
675+ throw(QString("evaluateInClosure: Script.require API object invalid in calling script"));
676+ }
677+ v8::Local<v8::Object> oldRequireObject = v8::Local<v8::Object>::Cast(oldRequireObjectValue);
678+
679+ v8::Local<v8::Value> newScriptObjectValue;
680+ if (!closureContext->Global()
681+ ->Get(closureContext, v8::String::NewFromUtf8(_v8Isolate, "Script").ToLocalChecked())
682+ .ToLocal(&newScriptObjectValue)) {
683+ Q_ASSERT(false); // This should never happen
684+ }
685+ if (!newScriptObjectValue->IsObject()) {
686+ Q_ASSERT(false); // This should never happen
687+ }
688+ v8::Local<v8::Object> newScriptObject = v8::Local<v8::Object>::Cast(newScriptObjectValue);
689+
690+ v8::Local<v8::Value> newRequireObjectValue;
691+ if (!newScriptObject->Get(closureContext, v8::String::NewFromUtf8(_v8Isolate, "require").ToLocalChecked())
692+ .ToLocal(&newRequireObjectValue)) {
693+ Q_ASSERT(false); // This should never happen
694+ }
695+ if (!newRequireObjectValue->IsObject()) {
696+ Q_ASSERT(false); // This should never happen
697+ }
698+ v8::Local<v8::Object> newRequireObject = v8::Local<v8::Object>::Cast(newRequireObjectValue);
699+
700+ auto requireMemberNames =
701+ oldRequireObject->GetPropertyNames(oldRequireObject->CreationContext()).ToLocalChecked();
702+ for (size_t i = 0; i < requireMemberNames->Length(); i++) {
703+ auto name = requireMemberNames->Get(closureContext, i).ToLocalChecked();
704+ v8::Local<v8::Value> oldObject;
705+ if (!oldRequireObject->Get(oldRequireObject->CreationContext(), name).ToLocal(&oldObject)) {
706+ Q_ASSERT(false); // This should never happen, the property has been reported as existing
707+ }
708+ if (!newRequireObject->Set(closureContext, name,oldObject).FromMaybe(false)) {
709+ Q_ASSERT(false);
710+ }
711+ }
712+ } catch (QString exception) {
713+ raiseException(exception);
714+ popContext();
715+ _evaluatingCounter--;
716+ return nullValue();
717+ }
718+
652719 auto maybeResult = program.constGet()->GetUnboundScript()->BindToCurrentContext()->Run(closureContext);
653720 v8::Local<v8::Value> v8Result;
654721 if (!maybeResult.ToLocal(&v8Result)) {
655722 v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Exception());
656723 QString errorMessage = QString(__FUNCTION__) + " hasCaught:" + QString(*utf8Value) + "\n"
657724 + "tryCatch details:" + formatErrorMessageFromTryCatch(tryCatch);
725+ v8Result = v8::Null(_v8Isolate);
658726 if (_manager) {
659727 _manager->scriptErrorMessage(errorMessage);
660728 } else {