History

Further exception work on V8

* Get rid of maybeEmitUncaughtException * Mostly get rid of makeError * Introduce exception hierarchy, change exceptions to shared_ptr * Simplify exception throwing code

Dale Glass committed 3 years ago

Commit 67e7a731 parent c0e62c510 files · +249 −260Browse files

Showing the changes to libraries/script-engine/src/ScriptManager.cpp (1 of 10 files). Show all

Unified · Split

libraries/script-engine/src/ScriptManager.cpp+34−28
@@ -282,6 +282,11 @@ ScriptManager::ScriptManager(Context context, const QString& scriptContents, con · 281 unmodified lines
282 processLevelMaxRetries = 1;282 processLevelMaxRetries = 1;
283 }283 }
284 284
285
286#if 0
287 // V8TODO: Is this actually needed? Exceptions will already be logged on the
288 // script engine side.
289
285 // this is where all unhandled exceptions end up getting logged290 // this is where all unhandled exceptions end up getting logged
286 connect(this, &ScriptManager::unhandledException, this, [this](const ScriptValue& err) {291 connect(this, &ScriptManager::unhandledException, this, [this](const ScriptValue& err) {
287 qCCritical(scriptengine) << "Caught exception";292 qCCritical(scriptengine) << "Caught exception";
@@ -296,6 +301,7 @@ ScriptManager::ScriptManager(Context context, const QString& scriptContents, con · 8 unmodified lines
296 301
297 logException(output);302 logException(output);
298 });303 });
304#endif
299 305
300 if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) {306 if (_type == Type::ENTITY_CLIENT || _type == Type::ENTITY_SERVER) {
301 QObject::connect(this, &ScriptManager::update, this, [this]() {307 QObject::connect(this, &ScriptManager::update, this, [this]() {
@@ -891,13 +897,11 @@ void ScriptManager::run() { · 589 unmodified lines
891 {897 {
892 PROFILE_RANGE(script, _fileNameString);898 PROFILE_RANGE(script, _fileNameString);
893 _returnValue = _engine->evaluate(_scriptContents, _fileNameString);899 _returnValue = _engine->evaluate(_scriptContents, _fileNameString);
894 _engine->maybeEmitUncaughtException(__FUNCTION__);
895 900
896 if (_engine->hasUncaughtException()) {901 if (_engine->hasUncaughtException()) {
897 902
898 qCWarning(scriptengine) << "Engine has uncaught exception, stopping";903 qCWarning(scriptengine) << "Engine has uncaught exception, stopping";
899 stop();904 stop();
900 emit unhandledException(_engine->cloneUncaughtException(__FUNCTION__));
901 _engine->clearExceptions();905 _engine->clearExceptions();
902 }906 }
903 }907 }
@@ -1023,7 +1027,7 @@ void ScriptManager::run() { · 119 unmodified lines
1023 if (!_engine->isEvaluating() && _engine->hasUncaughtException()) {1027 if (!_engine->isEvaluating() && _engine->hasUncaughtException()) {
1024 qCWarning(scriptengine) << __FUNCTION__ << "---------- UNCAUGHT EXCEPTION --------";1028 qCWarning(scriptengine) << __FUNCTION__ << "---------- UNCAUGHT EXCEPTION --------";
1025 qCWarning(scriptengine) << "runInThread" << _engine->uncaughtException();1029 qCWarning(scriptengine) << "runInThread" << _engine->uncaughtException();
1026 emit unhandledException(_engine->cloneUncaughtException(__FUNCTION__));1030 emit unhandledException(_engine->uncaughtException());
1027 _engine->clearExceptions();1031 _engine->clearExceptions();
1028 }1032 }
1029 }1033 }
@@ -1258,9 +1262,8 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r · 228 unmodified lines
1258 }1262 }
1259 auto message = QString("Cannot find module '%1' (%2)").arg(displayId);1263 auto message = QString("Cannot find module '%1' (%2)").arg(displayId);
1260 1264
1261 auto throwResolveError = [&](const ScriptValue& error) -> QString {1265 auto throwResolveError = [&](const QString& error, const QString &details = QString()) -> QString {
1262 _engine->raiseException(error);1266 _engine->raiseException(error, "require.resolve: " + details);
1263 _engine->maybeEmitUncaughtException("require.resolve");
1264 return QString();1267 return QString();
1265 };1268 };
1266 1269
@@ -1269,7 +1272,7 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r · 2 unmodified lines
1269 if (idLength < 1 || idLength > MAX_MODULE_ID_LENGTH) {1272 if (idLength < 1 || idLength > MAX_MODULE_ID_LENGTH) {
1270 auto details = QString("rejecting invalid module id size (%1 chars [1,%2])")1273 auto details = QString("rejecting invalid module id size (%1 chars [1,%2])")
1271 .arg(idLength).arg(MAX_MODULE_ID_LENGTH);1274 .arg(idLength).arg(MAX_MODULE_ID_LENGTH);
1272 return throwResolveError(_engine->makeError(_engine->newValue(message.arg(details)), "RangeError"));1275 return throwResolveError(details, "RangeError");
1273 }1276 }
1274 1277
1275 // this regex matches: absolute, dotted or path-like URLs1278 // this regex matches: absolute, dotted or path-like URLs
@@ -1296,15 +1299,15 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r · 20 unmodified lines
1296 if (QFileInfo(unanchoredUrl.toLocalFile()).isFile()) {1299 if (QFileInfo(unanchoredUrl.toLocalFile()).isFile()) {
1297 auto msg = QString("relative module ids must be anchored; use './%1' instead")1300 auto msg = QString("relative module ids must be anchored; use './%1' instead")
1298 .arg(moduleId);1301 .arg(moduleId);
1299 return throwResolveError(_engine->makeError(_engine->newValue(message.arg(msg))));1302 return throwResolveError(message.arg(msg));
1300 }1303 }
1301 }1304 }
1302 return throwResolveError(_engine->makeError(_engine->newValue(message.arg("system module not found"))));1305 return throwResolveError(message.arg("system module not found"));
1303 }1306 }
1304 }1307 }
1305 1308
1306 if (url.isRelative()) {1309 if (url.isRelative()) {
1307 return throwResolveError(_engine->makeError(_engine->newValue(message.arg("could not resolve module id"))));1310 return throwResolveError(message.arg("could not resolve module id"));
1308 }1311 }
1309 1312
1310 // if it looks like a local file, verify that it's an allowed path and really a file1313 // if it looks like a local file, verify that it's an allowed path and really a file
@@ -1317,22 +1320,21 @@ QString ScriptManager::_requireResolve(const QString& moduleId, const QString& r · 6 unmodified lines
1317 1320
1318 bool disallowOutsideFiles = !PathUtils::defaultScriptsLocation().isParentOf(canonical) && !currentSandboxURL.isLocalFile();1321 bool disallowOutsideFiles = !PathUtils::defaultScriptsLocation().isParentOf(canonical) && !currentSandboxURL.isLocalFile();
1319 if (disallowOutsideFiles && !PathUtils::isDescendantOf(canonical, currentSandboxURL)) {1322 if (disallowOutsideFiles && !PathUtils::isDescendantOf(canonical, currentSandboxURL)) {
1320 return throwResolveError(_engine->makeError(_engine->newValue(message.arg(1323 return throwResolveError(message.arg(
1321 QString("path '%1' outside of origin script '%2' '%3'")1324 QString("path '%1' outside of origin script '%2' '%3'")
1322 .arg(PathUtils::stripFilename(url))1325 .arg(PathUtils::stripFilename(url))
1323 .arg(PathUtils::stripFilename(currentSandboxURL))1326 .arg(PathUtils::stripFilename(currentSandboxURL))
1324 .arg(canonical.toString())1327 .arg(canonical.toString())
1325 ))));1328 ));
1326 }1329 }
1327 if (!file.exists()) {1330 if (!file.exists()) {
1328 return throwResolveError(_engine->makeError(_engine->newValue(message.arg("path does not exist: " + url.toLocalFile()))));1331 return throwResolveError(message.arg("path does not exist: " + url.toLocalFile()));
1329 }1332 }
1330 if (!file.isFile()) {1333 if (!file.isFile()) {
1331 return throwResolveError(_engine->makeError(_engine->newValue(message.arg("path is not a file: " + url.toLocalFile()))));1334 return throwResolveError(message.arg("path is not a file: " + url.toLocalFile()));
1332 }1335 }
1333 }1336 }
1334 1337
1335 _engine->maybeEmitUncaughtException(__FUNCTION__);
1336 return url.toString();1338 return url.toString();
1337}1339}
1338 1340
@@ -1488,7 +1490,7 @@ ScriptValue ScriptManager::instantiateModule(const ScriptValue& module, const QS · 149 unmodified lines
1488 //_engine->scriptValueDebugDetails(module);1490 //_engine->scriptValueDebugDetails(module);
1489 result = _engine->evaluateInClosure(closure, _engine->newProgram( sourceCode, modulePath ));1491 result = _engine->evaluateInClosure(closure, _engine->newProgram( sourceCode, modulePath ));
1490 }1492 }
1491 _engine->maybeEmitUncaughtException(__FUNCTION__);1493
1492 return result;1494 return result;
1493}1495}
1494 1496
@@ -1510,9 +1512,8 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 15 unmodified lines
1510#ifdef DEBUG_JS_MODULES1512#ifdef DEBUG_JS_MODULES
1511 qCWarning(scriptengine_module) << "throwing module error:" << error.toString() << modulePath << error.property("stack").toString();1513 qCWarning(scriptengine_module) << "throwing module error:" << error.toString() << modulePath << error.property("stack").toString();
1512#endif1514#endif
1513 _engine->raiseException(error);1515 _engine->raiseException(error, "module error");
1514 }1516 }
1515 _engine->maybeEmitUncaughtException("module");
1516 return _engine->nullValue();1517 return _engine->nullValue();
1517 };1518 };
1518 1519
@@ -1520,7 +1521,6 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 1 unmodified line
1520 QString modulePath = _requireResolve(moduleId);1521 QString modulePath = _requireResolve(moduleId);
1521 if (modulePath.isNull() || _engine->hasUncaughtException()) {1522 if (modulePath.isNull() || _engine->hasUncaughtException()) {
1522 // the resolver already threw an exception -- bail early1523 // the resolver already threw an exception -- bail early
1523 _engine->maybeEmitUncaughtException(__FUNCTION__);
1524 return _engine->nullValue();1524 return _engine->nullValue();
1525 }1525 }
1526 1526
@@ -1546,7 +1546,6 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 19 unmodified lines
1546 qCDebug(scriptengine_module) << QString("require - using cached module for '%1' (loaded: %2)")1546 qCDebug(scriptengine_module) << QString("require - using cached module for '%1' (loaded: %2)")
1547 .arg(moduleId).arg(module.property("loaded").toString());1547 .arg(moduleId).arg(module.property("loaded").toString());
1548 registerModuleWithParent(module, parent);1548 registerModuleWithParent(module, parent);
1549 _engine->maybeEmitUncaughtException("cached module");
1550 return exports;1549 return exports;
1551 }1550 }
1552 1551
@@ -1594,7 +1593,6 @@ ScriptValue ScriptManager::require(const QString& moduleId) { · 41 unmodified lines
1594 1593
1595 //qCDebug(scriptengine_module) << "//ScriptManager::require(" << moduleId << ")";1594 //qCDebug(scriptengine_module) << "//ScriptManager::require(" << moduleId << ")";
1596 1595
1597 _engine->maybeEmitUncaughtException(__FUNCTION__);
1598 //qCDebug(scriptengine_module) << "Exports: " << _engine->scriptValueDebugDetails(module.property("exports"));1596 //qCDebug(scriptengine_module) << "Exports: " << _engine->scriptValueDebugDetails(module.property("exports"));
1599 return module.property("exports");1597 return module.property("exports");
1600}1598}
@@ -1670,7 +1668,9 @@ void ScriptManager::include(const QStringList& includeFiles, const ScriptValue& · 69 unmodified lines
1670 1668
1671 doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation);1669 doWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, operation);
1672 if(_engine->hasUncaughtException()) {1670 if(_engine->hasUncaughtException()) {
1673 emit unhandledException(_engine->cloneUncaughtException("evaluateInclude"));1671 auto ex = _engine->uncaughtException();
1672 ex->additionalInfo += "; evaluateInClosure";
1673 emit unhandledException(ex);
1674 _engine->clearExceptions();1674 _engine->clearExceptions();
1675 }1675 }
1676 } else {1676 } else {
@@ -1995,11 +1995,14 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c · 318 unmodified lines
1995 //syntaxError.setProperty("detail", entityID.toString());1995 //syntaxError.setProperty("detail", entityID.toString());
1996 //V8TODO1996 //V8TODO
1997 //emit unhandledException(syntaxError);1997 //emit unhandledException(syntaxError);
1998
1998 return;1999 return;
1999 }2000 }
2000 if (!program) {2001 if (!program) {
2001 setError("Bad program (isNull)", EntityScriptStatus::ERROR_RUNNING_SCRIPT);2002 setError("Bad program (isNull)", EntityScriptStatus::ERROR_RUNNING_SCRIPT);
2002 emit unhandledException(_engine->makeError(_engine->newValue("program.isNull")));2003 std::shared_ptr<ScriptException> ex = std::make_shared<ScriptEngineException>("Program is Null", "Bad program in entityScriptContentAvailable");
2004 emit unhandledException(ex);
2005
2003 return; // done processing script2006 return; // done processing script
2004 }2007 }
2005 2008
@@ -2163,7 +2166,10 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c · 157 unmodified lines
2163 entityScriptObject = entityScriptConstructor.construct();2166 entityScriptObject = entityScriptConstructor.construct();
2164 2167
2165 if (_engine->hasUncaughtException()) {2168 if (_engine->hasUncaughtException()) {
2166 entityScriptObject = _engine->cloneUncaughtException("(construct " + entityID.toString() + ")");2169 // V8TODO: Why were we copying the uncaught exception here? Does anything
2170 // actually make use of that?
2171 // entityScriptObject = _engine->cloneUncaughtException("(construct " + entityID.toString() + ")");
2172 entityScriptObject = _engine->nullValue();
2167 _engine->clearExceptions();2173 _engine->clearExceptions();
2168 }2174 }
2169 };2175 };
@@ -2171,9 +2177,10 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c · 1 unmodified line
2171 doWithEnvironment(entityID, sandboxURL, initialization);2177 doWithEnvironment(entityID, sandboxURL, initialization);
2172 2178
2173 if (entityScriptObject.isError()) {2179 if (entityScriptObject.isError()) {
2174 auto exception = entityScriptObject;2180 // auto exception = entityScriptObject;
2175 setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT);2181 // setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT);
2176 emit unhandledException(exception);2182 // emit unhandledException(exception);
2183 // V8TODO: Is this needed? Wouldn't the ScriptManager have already emitted the exception?
2177 return;2184 return;
2178 }2185 }
2179 2186
@@ -2340,7 +2347,6 @@ void ScriptManager::doWithEnvironment(const EntityItemID& entityID, const QUrl& · 160 unmodified lines
2340#else2347#else
2341 operation();2348 operation();
2342#endif2349#endif
2343 _engine->maybeEmitUncaughtException(!entityID.isNull() ? entityID.toString() : __FUNCTION__);
2344 currentEntityIdentifier = oldIdentifier;2350 currentEntityIdentifier = oldIdentifier;
2345 currentSandboxURL = oldSandboxURL;2351 currentSandboxURL = oldSandboxURL;
2346}2352}