From 8f75ee78746a311434db3fe5a3793c6f725fa210 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 9 Apr 2010 14:15:07 +0200 Subject: Updated WebKit from /home/shausman/src/webkit/trunk to qtwebkit/qtwebkit-4.6 ( 14feb62c96ffe2c37e3e2fdac4e370fdbc76ef62 ) Changes in WebKit/qt since the last update: * r51006 -- https://bugs.webkit.org/show_bug.cgi?id=31475 -- Crash in StringHash::equal due to unaligned string data --- src/3rdparty/webkit/VERSION | 2 +- src/3rdparty/webkit/WebCore/ChangeLog | 13 +++++++++++++ .../webkit/WebCore/plugins/symbian/PluginViewSymbian.cpp | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/3rdparty/webkit/VERSION b/src/3rdparty/webkit/VERSION index 45608c5..7c9ea04 100644 --- a/src/3rdparty/webkit/VERSION +++ b/src/3rdparty/webkit/VERSION @@ -8,4 +8,4 @@ The commit imported was from the and has the sha1 checksum - e3dc4ef2b801d91e115c54f833fa7766d392ceda + 14feb62c96ffe2c37e3e2fdac4e370fdbc76ef62 diff --git a/src/3rdparty/webkit/WebCore/ChangeLog b/src/3rdparty/webkit/WebCore/ChangeLog index a2bd5c3..b7e46c7 100644 --- a/src/3rdparty/webkit/WebCore/ChangeLog +++ b/src/3rdparty/webkit/WebCore/ChangeLog @@ -1,3 +1,16 @@ +2010-04-09 David Leong + + Reviewed by Simon Hausmann. + + [Qt] Symbian apps crash on exit due to a bad qObject_cast. + + https://bugs.webkit.org/show_bug.cgi?id=37303 + + Added check for NULL to avoid the crash. + + * plugins/symbian/PluginViewSymbian.cpp: + (WebCore::PluginView::platformDestroy): + 2009-11-15 Dave Tapuska Reviewed by George Staikos. diff --git a/src/3rdparty/webkit/WebCore/plugins/symbian/PluginViewSymbian.cpp b/src/3rdparty/webkit/WebCore/plugins/symbian/PluginViewSymbian.cpp index 86f5f6c..0cce1fd 100644 --- a/src/3rdparty/webkit/WebCore/plugins/symbian/PluginViewSymbian.cpp +++ b/src/3rdparty/webkit/WebCore/plugins/symbian/PluginViewSymbian.cpp @@ -453,7 +453,7 @@ bool PluginView::platformStart() void PluginView::platformDestroy() { QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); - if (QGraphicsWebView *webView = qobject_cast(client->pluginParent())) + if (client && qobject_cast(client->pluginParent())) delete static_cast(platformPluginWidget())->proxy(); else delete platformPluginWidget(); -- cgit v0.12 From 06add85eb8a9bd8f53acd162ce665d46e7ebc137 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 9 Apr 2010 15:43:35 +0200 Subject: Regressions in Global Object prototype access In 4.5, changing the prototype of the (custom) global object used to "Just Work"(tm). In the JSC-based back-end, the built-in global object acts as a proxy if a custom global object is set, because JSC doesn't (yet, anyway) provide a way to replace the global object. To complicate this further, we also have a proxy to the original global object (that bypasses the custom global object proxying (!)). This is so that properties of the original global object can still be accessed with the QtScript C++ API when a custom global object has been set. Unfortunately, JSObject::prototype()/setPrototype() are not virtual, meaning that a change of prototype in the source object is not reflected in the proxy or vice versa. Work around this for now by syncing the prototype at the appropriate places (QScriptEngine::setGlobalObject(), QScriptValue::setPrototype()). This fixes all except the case when a prototype is set from JS, since such a write doesn't go through our public C++ API. But this case can be detected and handled by the global object's JSObject::put() reimplementation. Created a separate report for that issue: QTBUG-9737. Task-number: QTBUG-7066 Reviewed-by: Jedrzej Nowacki --- src/script/api/qscriptengine.cpp | 8 +- src/script/api/qscriptvalue.cpp | 13 ++- tests/auto/qscriptengine/tst_qscriptengine.cpp | 127 +++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 4 deletions(-) diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index d6d1367..2422108 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -1007,11 +1007,15 @@ void QScriptEnginePrivate::setGlobalObject(JSC::JSObject *object) if (object == globalObject()) return; QScript::GlobalObject *glob = static_cast(originalGlobalObject()); - if (object == originalGlobalObjectProxy) + if (object == originalGlobalObjectProxy) { glob->customGlobalObject = 0; - else { + // Sync the internal prototype, since JSObject::prototype() is not virtual. + glob->setPrototype(originalGlobalObjectProxy->prototype()); + } else { Q_ASSERT(object != originalGlobalObject()); glob->customGlobalObject = object; + // Sync the internal prototype, since JSObject::prototype() is not virtual. + glob->setPrototype(object->prototype()); } } diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index 8cf01e7..79d5dcb 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -792,19 +792,28 @@ void QScriptValue::setPrototype(const QScriptValue &prototype) "a different engine"); return; } + JSC::JSObject *thisObject = JSC::asObject(d->jscValue); JSC::JSValue other = d->engine->scriptValueToJSCValue(prototype); // check for cycle JSC::JSValue nextPrototypeValue = other; while (nextPrototypeValue && nextPrototypeValue.isObject()) { JSC::JSObject *nextPrototype = JSC::asObject(nextPrototypeValue); - if (nextPrototype == JSC::asObject(d->jscValue)) { + if (nextPrototype == thisObject) { qWarning("QScriptValue::setPrototype() failed: cyclic prototype value"); return; } nextPrototypeValue = nextPrototype->prototype(); } - JSC::asObject(d->jscValue)->setPrototype(other); + + thisObject->setPrototype(other); + + // Sync the internal Global Object prototype if appropriate. + if (((thisObject == d->engine->originalGlobalObjectProxy) + && !d->engine->customGlobalObject()) + || (thisObject == d->engine->customGlobalObject())) { + d->engine->originalGlobalObject()->setPrototype(other); + } } /*! diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index cbc36a7..f556fa1 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -104,6 +104,8 @@ private slots: void getSetGlobalObject(); void globalObjectProperties(); void globalObjectGetterSetterProperty(); + void customGlobalObjectWithPrototype(); + void globalObjectWithCustomPrototype(); void builtinFunctionNames_data(); void builtinFunctionNames(); void checkSyntax_data(); @@ -1174,6 +1176,131 @@ void tst_QScriptEngine::globalObjectGetterSetterProperty() QVERIFY(global.property("baz").equals(789)); } +void tst_QScriptEngine::customGlobalObjectWithPrototype() +{ + for (int x = 0; x < 2; ++x) { + QScriptEngine engine; + QScriptValue wrap = engine.newObject(); + QScriptValue global = engine.globalObject(); + QScriptValue originalGlobalProto = global.prototype(); + if (!x) { + // Set prototype before setting global object + wrap.setPrototype(global); + QVERIFY(wrap.prototype().strictlyEquals(global)); + engine.setGlobalObject(wrap); + } else { + // Set prototype after setting global object + engine.setGlobalObject(wrap); + wrap.setPrototype(global); + QVERIFY(wrap.prototype().strictlyEquals(global)); + } + { + QScriptValue ret = engine.evaluate("print"); + QVERIFY(ret.isFunction()); + QVERIFY(ret.strictlyEquals(wrap.property("print"))); + } + { + QScriptValue ret = engine.evaluate("this.print"); + QVERIFY(ret.isFunction()); + QVERIFY(ret.strictlyEquals(wrap.property("print"))); + } + { + QScriptValue ret = engine.evaluate("hasOwnProperty('print')"); + QVERIFY(ret.isBool()); + QVERIFY(!ret.toBool()); + } + { + QScriptValue ret = engine.evaluate("this.hasOwnProperty('print')"); + QVERIFY(ret.isBool()); + QVERIFY(!ret.toBool()); + } + + QScriptValue anotherProto = engine.newObject(); + anotherProto.setProperty("anotherProtoProperty", 123); + global.setPrototype(anotherProto); + { + QScriptValue ret = engine.evaluate("print"); + QVERIFY(ret.isFunction()); + QVERIFY(ret.strictlyEquals(wrap.property("print"))); + } + { + QScriptValue ret = engine.evaluate("anotherProtoProperty"); + QVERIFY(ret.isNumber()); + QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty"))); + } + { + QScriptValue ret = engine.evaluate("this.anotherProtoProperty"); + QVERIFY(ret.isNumber()); + QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty"))); + } + + wrap.setPrototype(anotherProto); + { + QScriptValue ret = engine.evaluate("print"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: print")); + } + { + QScriptValue ret = engine.evaluate("anotherProtoProperty"); + QVERIFY(ret.isNumber()); + QVERIFY(ret.strictlyEquals(wrap.property("anotherProtoProperty"))); + } + QVERIFY(global.prototype().strictlyEquals(anotherProto)); + + global.setPrototype(originalGlobalProto); + engine.setGlobalObject(global); + { + QScriptValue ret = engine.evaluate("anotherProtoProperty"); + QVERIFY(ret.isError()); + QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: anotherProtoProperty")); + } + { + QScriptValue ret = engine.evaluate("print"); + QVERIFY(ret.isFunction()); + QVERIFY(ret.strictlyEquals(global.property("print"))); + } + QVERIFY(!anotherProto.property("print").isValid()); + } +} + +void tst_QScriptEngine::globalObjectWithCustomPrototype() +{ + QScriptEngine engine; + QScriptValue proto = engine.newObject(); + proto.setProperty("protoProperty", 123); + QScriptValue global = engine.globalObject(); + QScriptValue originalProto = global.prototype(); + global.setPrototype(proto); + { + QScriptValue ret = engine.evaluate("protoProperty"); + QVERIFY(ret.isNumber()); + QVERIFY(ret.strictlyEquals(global.property("protoProperty"))); + } + { + QScriptValue ret = engine.evaluate("this.protoProperty"); + QVERIFY(ret.isNumber()); + QVERIFY(ret.strictlyEquals(global.property("protoProperty"))); + } + { + QScriptValue ret = engine.evaluate("hasOwnProperty('protoProperty')"); + QVERIFY(ret.isBool()); + QVERIFY(!ret.toBool()); + } + { + QScriptValue ret = engine.evaluate("this.hasOwnProperty('protoProperty')"); + QVERIFY(ret.isBool()); + QVERIFY(!ret.toBool()); + } + + // Custom prototype set from JS + { + QScriptValue ret = engine.evaluate("this.__proto__ = { 'a': 123 }; a"); + QVERIFY(ret.isNumber()); + QEXPECT_FAIL("", "QTBUG-9737", Continue); + QVERIFY(ret.strictlyEquals(global.property("a"))); + } +} + void tst_QScriptEngine::builtinFunctionNames_data() { QTest::addColumn("expression"); -- cgit v0.12