diff options
author | Kent Hansen <kent.hansen@nokia.com> | 2012-08-16 14:11:52 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-08-20 13:24:31 +0200 |
commit | cd6eabb2d68321536c7fbc032a2a93990e891936 (patch) | |
tree | 9f3ed5952f5da0da1ed3ee4959f891fcad9d4d42 /src/qml/qml/v8/qv8jsonwrapper.cpp | |
parent | 2791a13757912cfd0d5cc6a83f228fab5c1645ae (diff) |
Use object identity to detect cycles in JS-to-C++ type conversion
The documentation for v8::Object::GetIdentityHash() states that the
hash value is not guaranteed to be unique (the current implementation
just returns a random number). Hence, the hash value should not be
used to determine whether an object has already been visited during
type conversion; in the worst (and non-deterministic) case, the
conversion will be "cut off" prematurely (due to identical hash
values for two different objects), resulting in data loss.
Instead, represent the visited objects as a set of V8 object handles.
This is safe since the type conversion is always done on the stack,
within a handle scope. Use v8::Object::GetIdentityHash() merely to
implement the qHash() specialization needed for the set.
V8 already provides an operator==() for handles, and it is documented
to return true "if the objects to which they refer are identical",
which is the behavior required by the set implementation.
Task-number: QTBUG-21681
Change-Id: I1f2a1eee8f7c197c02c2ffeaaa1fc0274e8ab740
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
Reviewed-by: Simon Hausmann <simon.hausmann@nokia.com>
Diffstat (limited to 'src/qml/qml/v8/qv8jsonwrapper.cpp')
-rw-r--r-- | src/qml/qml/v8/qv8jsonwrapper.cpp | 20 |
1 files changed, 9 insertions, 11 deletions
diff --git a/src/qml/qml/v8/qv8jsonwrapper.cpp b/src/qml/qml/v8/qv8jsonwrapper.cpp index ff8b69f580..5ba59b2263 100644 --- a/src/qml/qml/v8/qv8jsonwrapper.cpp +++ b/src/qml/qml/v8/qv8jsonwrapper.cpp @@ -82,7 +82,7 @@ v8::Handle<v8::Value> QV8JsonWrapper::fromJsonValue(const QJsonValue &value) } QJsonValue QV8JsonWrapper::toJsonValue(v8::Handle<v8::Value> value, - QSet<int> &visitedObjects) + V8ObjectSet &visitedObjects) { if (value->IsString()) return QJsonValue(QJSConverter::toString(value.As<v8::String>())); @@ -109,22 +109,21 @@ v8::Local<v8::Object> QV8JsonWrapper::fromJsonObject(const QJsonObject &object) } QJsonObject QV8JsonWrapper::toJsonObject(v8::Handle<v8::Value> value, - QSet<int> &visitedObjects) + V8ObjectSet &visitedObjects) { QJsonObject result; if (!value->IsObject() || value->IsArray() || value->IsFunction()) return result; v8::Handle<v8::Object> v8object(value.As<v8::Object>()); - int hash = v8object->GetIdentityHash(); - if (visitedObjects.contains(hash)) { + if (visitedObjects.contains(v8object)) { // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty object (and no error is thrown). return result; } - visitedObjects.insert(hash); + visitedObjects.insert(v8object); v8::Local<v8::Array> propertyNames = m_engine->getOwnPropertyNames(v8object); uint32_t length = propertyNames->Length(); @@ -136,7 +135,7 @@ QJsonObject QV8JsonWrapper::toJsonObject(v8::Handle<v8::Value> value, toJsonValue(propertyValue, visitedObjects)); } - visitedObjects.remove(hash); + visitedObjects.remove(v8object); return result; } @@ -151,22 +150,21 @@ v8::Local<v8::Array> QV8JsonWrapper::fromJsonArray(const QJsonArray &array) } QJsonArray QV8JsonWrapper::toJsonArray(v8::Handle<v8::Value> value, - QSet<int> &visitedObjects) + V8ObjectSet &visitedObjects) { QJsonArray result; if (!value->IsArray()) return result; v8::Handle<v8::Array> v8array(value.As<v8::Array>()); - int hash = v8array->GetIdentityHash(); - if (visitedObjects.contains(hash)) { + if (visitedObjects.contains(v8array)) { // Avoid recursion. // For compatibility with QVariant{List,Map} conversion, we return an // empty array (and no error is thrown). return result; } - visitedObjects.insert(hash); + visitedObjects.insert(v8array); uint32_t length = v8array->Length(); for (uint32_t i = 0; i < length; ++i) { @@ -175,7 +173,7 @@ QJsonArray QV8JsonWrapper::toJsonArray(v8::Handle<v8::Value> value, result.append(toJsonValue(element, visitedObjects)); } - visitedObjects.remove(hash); + visitedObjects.remove(v8array); return result; } |