From 4f35280bd039c2d2f0c53e936740440f1d887916 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 21 Aug 2013 12:30:46 +0200 Subject: Debugger: Fix crash when app exits while debugging Make sure we don't access an already deleted v8engine any more. Task-number: QTBUG-33100 Change-Id: Ic517577ae30b41375cbf9f787cfe0a29121171e2 Reviewed-by: Aurindam Jana --- src/qml/debugger/qv8debugservice.cpp | 11 ++++- src/qml/debugger/qv8debugservice_p.h | 3 +- src/qml/qml/qqmlengine.cpp | 3 +- tests/auto/qml/debugger/qqmldebugjs/data/quit.qml | 53 ++++++++++++++++++++++ .../qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp | 25 ++++++++++ tests/auto/qml/debugger/shared/debugutil.cpp | 10 ++++ tests/auto/qml/debugger/shared/debugutil_p.h | 3 ++ 7 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 tests/auto/qml/debugger/qqmldebugjs/data/quit.qml diff --git a/src/qml/debugger/qv8debugservice.cpp b/src/qml/debugger/qv8debugservice.cpp index 9045b4b50e..575097f829 100644 --- a/src/qml/debugger/qv8debugservice.cpp +++ b/src/qml/debugger/qv8debugservice.cpp @@ -148,12 +148,18 @@ QV8DebugService *QV8DebugService::instance() return v8ServiceInstance(); } -void QV8DebugService::initialize(const QV8Engine *engine) +void QV8DebugService::addEngine(const QV8Engine *engine) { // just make sure that the service is properly registered v8ServiceInstance()->setEngine(engine); } +void QV8DebugService::removeEngine(const QV8Engine *engine) +{ + if (v8ServiceInstance()->d_func()->engine == engine) + v8ServiceInstance()->setEngine(0); +} + void QV8DebugService::setEngine(const QV8Engine *engine) { Q_D(QV8DebugService); @@ -280,7 +286,8 @@ void QV8DebugService::processDebugMessages() { Q_D(QV8DebugService); v8::HandleScope handleScope; - v8::Context::Scope contextScope(d->engine->context()); + if (d->engine) + v8::Context::Scope contextScope(d->engine->context()); v8::Debug::ProcessDebugMessages(); } diff --git a/src/qml/debugger/qv8debugservice_p.h b/src/qml/debugger/qv8debugservice_p.h index e6f05a2397..75fd69290c 100644 --- a/src/qml/debugger/qv8debugservice_p.h +++ b/src/qml/debugger/qv8debugservice_p.h @@ -75,7 +75,8 @@ public: ~QV8DebugService(); static QV8DebugService *instance(); - static void initialize(const QV8Engine *engine); + static void addEngine(const QV8Engine *engine); + static void removeEngine(const QV8Engine *engine); void debugMessageHandler(const QString &message); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index fef3dd21fe..cc49b4f0a2 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -749,7 +749,7 @@ void QQmlEnginePrivate::init() QQmlEngineDebugService::isDebuggingEnabled()) { isDebugging = true; QQmlEngineDebugService::instance()->addEngine(q); - QV8DebugService::initialize(v8engine()); + QV8DebugService::addEngine(v8engine()); QV8ProfilerService::initialize(); QQmlProfilerService::initialize(); QDebugMessageService::instance(); @@ -838,6 +838,7 @@ QQmlEngine::~QQmlEngine() Q_D(QQmlEngine); if (d->isDebugging) { QQmlEngineDebugService::instance()->remEngine(this); + QV8DebugService::removeEngine(handle()); } // Emit onDestruction signals for the root context before diff --git a/tests/auto/qml/debugger/qqmldebugjs/data/quit.qml b/tests/auto/qml/debugger/qqmldebugjs/data/quit.qml new file mode 100644 index 0000000000..47acceba2a --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugjs/data/quit.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +//DO NOT CHANGE + +Item { + Timer { + running: true + triggeredOnStart: true + onTriggered: Qt.quit(); + } +} + diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp index 424a3b36ac..e5a7af630a 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp @@ -139,6 +139,7 @@ const char *EXCEPTION_QMLFILE = "exception.qml"; const char *ONCOMPLETED_QMLFILE = "oncompleted.qml"; const char *CREATECOMPONENT_QMLFILE = "createComponent.qml"; const char *CONDITION_QMLFILE = "condition.qml"; +const char *QUIT_QMLFILE = "quit.qml"; const char *CHANGEBREAKPOINT_QMLFILE = "changeBreakpoint.qml"; const char *STEPACTION_QMLFILE = "stepAction.qml"; const char *BREAKPOINTRELOCATION_QMLFILE = "breakpointRelocation.qml"; @@ -196,6 +197,7 @@ private slots: void setBreakpointInScriptOnEmptyLine(); void setBreakpointInScriptOnOptimizedBinding(); void setBreakpointInScriptWithCondition(); + void setBreakpointInScriptThatQuits(); //void setBreakpointInFunction(); //NOT SUPPORTED void setBreakpointOnEvent(); // void setBreakpointWhenAttaching(); @@ -1338,6 +1340,29 @@ void tst_QQmlDebugJS::setBreakpointInScriptWithCondition() QVERIFY(body.value("value").toInt() > out); } +void tst_QQmlDebugJS::setBreakpointInScriptThatQuits() +{ + QVERIFY(init(QUIT_QMLFILE)); + + int sourceLine = 49; + + client->setBreakpoint(QLatin1String(SCRIPTREGEXP), QLatin1String(QUIT_QMLFILE), sourceLine, -1, true); + client->connect(); + QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + + QString jsonString(client->response); + QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + + QVariantMap body = value.value("body").toMap(); + + QCOMPARE(body.value("sourceLine").toInt(), sourceLine); + QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(QUIT_QMLFILE)); + + client->continueDebugging(QJSDebugClient::Continue); + QVERIFY(process->waitForFinished()); + QCOMPARE(process->exitStatus(), QProcess::NormalExit); +} + /* TODO fails because of a race condition when starting up the engine before the view void tst_QQmlDebugJS::setBreakpointWhenAttaching() { diff --git a/tests/auto/qml/debugger/shared/debugutil.cpp b/tests/auto/qml/debugger/shared/debugutil.cpp index ff3140f520..ab27337d41 100644 --- a/tests/auto/qml/debugger/shared/debugutil.cpp +++ b/tests/auto/qml/debugger/shared/debugutil.cpp @@ -168,6 +168,16 @@ int QQmlDebugProcess::debugPort() const return m_port; } +bool QQmlDebugProcess::waitForFinished() +{ + return m_process.waitForFinished(); +} + +QProcess::ExitStatus QQmlDebugProcess::exitStatus() const +{ + return m_process.exitStatus(); +} + void QQmlDebugProcess::setEnvironment(const QStringList &environment) { m_environment = environment; diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h index 11b16a1fb8..9f9a852fb6 100644 --- a/tests/auto/qml/debugger/shared/debugutil_p.h +++ b/tests/auto/qml/debugger/shared/debugutil_p.h @@ -95,6 +95,9 @@ public: bool waitForSessionStart(); int debugPort() const; + bool waitForFinished(); + QProcess::ExitStatus exitStatus() const; + QString output() const; void stop(); -- cgit v1.2.3