QML Debugger: Don't crash when looking up values from imported modules
We cannot look up the imports from other modules because those are
stored in the CU. But we can avoid the crash.
Pick-to: 6.5 6.2 5.15
Fixes: QTBUG-117479
Change-Id: Ib5660c94dfb7ed20baedf7f71b2f175e6be042b1
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit 604da0a395
)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
c8ad0a547e
commit
5e34cf7256
|
@ -188,9 +188,10 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
|
|||
QV4::ScopedValue v(scope);
|
||||
QV4::Heap::InternalClass *ic = ctxt->internalClass();
|
||||
for (uint i = 0; i < ic->size; ++i) {
|
||||
QString name = ic->keyAt(i);
|
||||
names.append(name);
|
||||
v = static_cast<QV4::Heap::CallContext *>(ctxt->d())->locals[i];
|
||||
QV4::ScopedValue stringOrSymbol(scope, ic->keyAt(i));
|
||||
QV4::ScopedString propName(scope, stringOrSymbol->toString(scope.engine));
|
||||
names.append(propName->toQString());
|
||||
v = ctxt->getProperty(propName);
|
||||
collectedRefs.append(addValueRef(v));
|
||||
}
|
||||
|
||||
|
|
|
@ -457,9 +457,10 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a
|
|||
QV4::Heap::InternalClass *ic = callContext->internalClass();
|
||||
QV4::ScopedValue v(scope);
|
||||
for (uint i = 0; i < ic->size; ++i) {
|
||||
QString name = ic->keyAt(i);
|
||||
v = callContext->d()->locals[i];
|
||||
collector.collect(&output, QString(), name, v);
|
||||
QV4::ScopedValue stringOrSymbol(scope, ic->keyAt(i));
|
||||
QV4::ScopedString propName(scope, stringOrSymbol->toString(scope.engine));
|
||||
v = callContext->getProperty(propName);
|
||||
collector.collect(&output, QString(), propName->toQString(), v);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1086,8 +1086,11 @@ QStringList QJSManagedValue::jsMetaMembers() const
|
|||
const int size = heapClass->size;
|
||||
QStringList result;
|
||||
result.reserve(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
result.append(heapClass->keyAt(i));
|
||||
QV4::Scope scope(c->engine());
|
||||
for (int i = 0; i < size; ++i) {
|
||||
QV4::ScopedValue key(scope, heapClass->keyAt(i));
|
||||
result.append(key->toQString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -299,9 +299,14 @@ ReturnedValue ExecutionContext::getProperty(String *name)
|
|||
case Heap::ExecutionContext::Type_CallContext: {
|
||||
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
|
||||
|
||||
uint index = c->internalClass->indexOfValueOrGetter(id);
|
||||
if (index < UINT_MAX)
|
||||
const uint index = c->internalClass->indexOfValueOrGetter(id);
|
||||
if (index < c->locals.alloc)
|
||||
return c->locals[index].asReturnedValue();
|
||||
|
||||
// TODO: We should look up the module imports here, but those are part of the CU:
|
||||
// imports[index - c->locals.size];
|
||||
// See QTBUG-118478
|
||||
|
||||
Q_FALLTHROUGH();
|
||||
}
|
||||
case Heap::ExecutionContext::Type_WithContext:
|
||||
|
@ -349,9 +354,14 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
|
|||
case Heap::ExecutionContext::Type_CallContext: {
|
||||
Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
|
||||
|
||||
uint index = c->internalClass->indexOfValueOrGetter(id);
|
||||
if (index < UINT_MAX)
|
||||
const uint index = c->internalClass->indexOfValueOrGetter(id);
|
||||
if (index < c->locals.alloc)
|
||||
return c->locals[index].asReturnedValue();
|
||||
|
||||
// TODO: We should look up the module imports here, but those are part of the CU:
|
||||
// imports[index - c->locals.size];
|
||||
// See QTBUG-118478
|
||||
|
||||
Q_FALLTHROUGH();
|
||||
}
|
||||
case Heap::ExecutionContext::Type_GlobalContext: {
|
||||
|
|
|
@ -280,9 +280,15 @@ void InternalClass::destroy()
|
|||
Base::destroy();
|
||||
}
|
||||
|
||||
QString InternalClass::keyAt(uint index) const
|
||||
ReturnedValue InternalClass::keyAt(uint index) const
|
||||
{
|
||||
return nameMap.at(index).toQString();
|
||||
PropertyKey key = nameMap.at(index);
|
||||
if (!key.isValid())
|
||||
return Encode::undefined();
|
||||
if (key.isArrayIndex())
|
||||
return Encode(key.asArrayIndex());
|
||||
Q_ASSERT(key.isStringOrSymbol());
|
||||
return key.asStringOrSymbol()->asReturnedValue();
|
||||
}
|
||||
|
||||
void InternalClass::changeMember(QV4::Object *object, PropertyKey id, PropertyAttributes data, InternalClassEntry *entry)
|
||||
|
|
|
@ -332,7 +332,7 @@ struct InternalClass : Base {
|
|||
void init(InternalClass *other);
|
||||
void destroy();
|
||||
|
||||
Q_QML_PRIVATE_EXPORT QString keyAt(uint index) const;
|
||||
Q_QML_PRIVATE_EXPORT ReturnedValue keyAt(uint index) const;
|
||||
Q_REQUIRED_RESULT InternalClass *nonExtensible();
|
||||
Q_REQUIRED_RESULT InternalClass *locked();
|
||||
|
||||
|
|
|
@ -223,9 +223,12 @@ OwnPropertyKeyIterator *Module::virtualOwnPropertyKeys(const Object *o, Value *t
|
|||
if (module->d()->unit->isESModule()) {
|
||||
names = module->d()->unit->exportedNames();
|
||||
} else {
|
||||
Heap::InternalClass *scopeClass = module->d()->scope->internalClass;
|
||||
for (uint i = 0; i < scopeClass->size; ++i)
|
||||
names << scopeClass->keyAt(i);
|
||||
QV4::Scope scope(module->engine());
|
||||
QV4::Scoped<InternalClass> scopeClass(scope, module->d()->scope->internalClass);
|
||||
for (uint i = 0, end = scopeClass->d()->size; i < end; ++i) {
|
||||
QV4::ScopedValue key(scope, scopeClass->d()->keyAt(i));
|
||||
names << key->toQString();
|
||||
}
|
||||
}
|
||||
|
||||
return new ModuleNamespaceIterator(names);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
import QtQml 2.15
|
||||
import "module1.js" as Module1
|
||||
|
||||
QtObject {}
|
|
@ -0,0 +1,5 @@
|
|||
.pragma library
|
||||
|
||||
.import "module2.mjs" as Module2
|
||||
|
||||
Module2.crashMe();
|
|
@ -0,0 +1,7 @@
|
|||
import * as Module3 from "module3.mjs"
|
||||
import * as Module4 from "module4.mjs"
|
||||
|
||||
export function crashMe()
|
||||
{
|
||||
console.log("Hello world!");
|
||||
}
|
|
@ -216,10 +216,14 @@ public:
|
|||
QJsonArray scopes = frameObj.value(QLatin1String("scopes")).toArray();
|
||||
int nscopes = scopes.size();
|
||||
int s = 0;
|
||||
for (s = 0; s < nscopes; ++s) {
|
||||
QJsonObject o = scopes.at(s).toObject();
|
||||
if (o.value(QLatin1String("type")).toInt(-2) == 1) // CallContext
|
||||
break;
|
||||
if (m_targetScope != -1) {
|
||||
s = m_targetScope;
|
||||
} else {
|
||||
for (s = 0; s < nscopes; ++s) {
|
||||
QJsonObject o = scopes.at(s).toObject();
|
||||
if (o.value(QLatin1String("type")).toInt(-2) == 1) // CallContext
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s == nscopes)
|
||||
return;
|
||||
|
@ -249,6 +253,7 @@ public:
|
|||
bool m_wasPaused;
|
||||
QV4Debugger::PauseReason m_pauseReason;
|
||||
bool m_captureContextInfo;
|
||||
int m_targetScope = -1;
|
||||
QList<QV4Debugger::ExecutionState> m_statesWhenPaused;
|
||||
QList<TestBreakPoint> m_breakPointsToAddWhenPaused;
|
||||
QVector<QV4::StackFrame> m_stackTrace;
|
||||
|
@ -323,6 +328,9 @@ private slots:
|
|||
void readThis();
|
||||
void signalParameters();
|
||||
void debuggerNoCrash();
|
||||
|
||||
void breakPointInJSModule();
|
||||
|
||||
private:
|
||||
QV4Debugger *debugger() const
|
||||
{
|
||||
|
@ -968,6 +976,35 @@ void tst_qv4debugger::debuggerNoCrash()
|
|||
debugThread->wait();
|
||||
}
|
||||
|
||||
void tst_qv4debugger::breakPointInJSModule()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
QV4::ExecutionEngine *v4 = engine.handle();
|
||||
QPointer<QV4Debugger> v4Debugger = new QV4Debugger(v4);
|
||||
v4->setDebugger(v4Debugger.data());
|
||||
|
||||
QScopedPointer<QThread> debugThread(new QThread);
|
||||
debugThread->start();
|
||||
QScopedPointer<TestAgent> debuggerAgent(new TestAgent(v4));
|
||||
debuggerAgent->addDebugger(v4Debugger);
|
||||
debuggerAgent->moveToThread(debugThread.data());
|
||||
|
||||
QQmlComponent component(&engine, testFileUrl("breakPointInJSModule.qml"));
|
||||
QVERIFY2(component.isReady(), qPrintable(component.errorString()));
|
||||
|
||||
debuggerAgent->m_captureContextInfo = true;
|
||||
debuggerAgent->m_targetScope = 1;
|
||||
v4Debugger->addBreakPoint("module2.mjs", 6);
|
||||
|
||||
QScopedPointer<QObject> obj(component.create());
|
||||
QVERIFY(!obj.isNull());
|
||||
|
||||
QVERIFY(!debuggerAgent->m_capturedScope.isEmpty());
|
||||
|
||||
debugThread->quit();
|
||||
debugThread->wait();
|
||||
}
|
||||
|
||||
tst_qv4debugger::tst_qv4debugger() : QQmlDataTest(QT_QMLTEST_DATADIR) { }
|
||||
|
||||
QTEST_MAIN(tst_qv4debugger)
|
||||
|
|
Loading…
Reference in New Issue