Index: content/child/v8_value_converter_impl.cc |
diff --git a/content/child/v8_value_converter_impl.cc b/content/child/v8_value_converter_impl.cc |
index dc32d9fd94961e2ea40ef9fd1bc756349b5fd999..7abff15196453b90eaec6c697edbcc2f03196cc9 100644 |
--- a/content/child/v8_value_converter_impl.cc |
+++ b/content/child/v8_value_converter_impl.cc |
@@ -91,33 +91,85 @@ class V8ValueConverterImpl::FromV8ValueState { |
// other handle B in the map points to the same object as A. Note that A can |
// be unique even if there already is another handle with the same identity |
// hash (key) in the map, because two objects can have the same hash. |
- bool UpdateAndCheckUniqueness(v8::Local<v8::Object> handle) { |
- typedef HashToHandleMap::const_iterator Iterator; |
- int hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash(); |
- // We only compare using == with handles to objects with the same identity |
- // hash. Different hash obviously means different objects, but two objects |
- // in a couple of thousands could have the same identity hash. |
- std::pair<Iterator, Iterator> range = unique_map_.equal_range(hash); |
- for (Iterator it = range.first; it != range.second; ++it) { |
- // Operator == for handles actually compares the underlying objects. |
- if (it->second == handle) |
- return false; |
- } |
+ bool AddToUniquenessCheck(v8::Local<v8::Object> handle) { |
+ int hash; |
+ Iterator iter = GetIteratorInMap(handle, &hash); |
+ if (iter != unique_map_.end()) |
+ return false; |
+ |
unique_map_.insert(std::make_pair(hash, handle)); |
return true; |
} |
+ bool RemoveFromUniquenessCheck(v8::Local<v8::Object> handle) { |
+ int unused_hash; |
+ Iterator iter = GetIteratorInMap(handle, &unused_hash); |
+ if (iter == unique_map_.end()) |
+ return false; |
+ unique_map_.erase(iter); |
+ return true; |
+ } |
+ |
bool HasReachedMaxRecursionDepth() { |
return max_recursion_depth_ < 0; |
} |
private: |
- typedef std::multimap<int, v8::Local<v8::Object> > HashToHandleMap; |
+ using HashToHandleMap = std::multimap<int, v8::Local<v8::Object>>; |
+ using Iterator = HashToHandleMap::const_iterator; |
+ |
+ Iterator GetIteratorInMap(v8::Local<v8::Object> handle, int* hash) { |
+ *hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash(); |
+ // We only compare using == with handles to objects with the same identity |
+ // hash. Different hash obviously means different objects, but two objects |
+ // in a couple of thousands could have the same identity hash. |
+ std::pair<Iterator, Iterator> range = unique_map_.equal_range(*hash); |
+ for (Iterator it = range.first; it != range.second; ++it) { |
+ // Operator == for handles actually compares the underlying objects. |
+ if (it->second == handle) |
+ return it; |
+ } |
+ // Not found. |
+ return unique_map_.end(); |
+ } |
+ |
HashToHandleMap unique_map_; |
int max_recursion_depth_; |
bool avoid_identity_hash_for_testing_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(FromV8ValueState); |
+}; |
+ |
+// A class to ensure that objects/arrays that are being converted by |
+// this V8ValueConverterImpl do not have cycles. |
+// |
+// An example of cycle: var v = {}; v = {key: v}; |
+// Not an example of cycle: var v = {}; a = [v, v]; or w = {a: v, b: v}; |
+class V8ValueConverterImpl::ScopedUniquenessGuard { |
+ public: |
+ ScopedUniquenessGuard(V8ValueConverterImpl::FromV8ValueState* state, |
+ v8::Local<v8::Object> value) |
+ : state_(state), |
+ value_(value), |
+ is_valid_(state_->AddToUniquenessCheck(value_)) {} |
+ ~ScopedUniquenessGuard() { |
+ if (is_valid_) { |
+ bool removed = state_->RemoveFromUniquenessCheck(value_); |
+ DCHECK(removed); |
+ } |
+ } |
+ |
+ bool is_valid() const { return is_valid_; } |
+ |
+ private: |
+ typedef std::multimap<int, v8::Local<v8::Object> > HashToHandleMap; |
+ V8ValueConverterImpl::FromV8ValueState* state_; |
+ v8::Local<v8::Object> value_; |
+ bool is_valid_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ScopedUniquenessGuard); |
}; |
V8ValueConverter* V8ValueConverter::create() { |
@@ -373,7 +425,8 @@ base::Value* V8ValueConverterImpl::FromV8Array( |
v8::Local<v8::Array> val, |
FromV8ValueState* state, |
v8::Isolate* isolate) const { |
- if (!state->UpdateAndCheckUniqueness(val)) |
+ ScopedUniquenessGuard uniqueness_guard(state, val); |
+ if (!uniqueness_guard.is_valid()) |
return base::Value::CreateNullValue().release(); |
std::unique_ptr<v8::Context::Scope> scope; |
@@ -458,7 +511,8 @@ base::Value* V8ValueConverterImpl::FromV8Object( |
v8::Local<v8::Object> val, |
FromV8ValueState* state, |
v8::Isolate* isolate) const { |
- if (!state->UpdateAndCheckUniqueness(val)) |
+ ScopedUniquenessGuard uniqueness_guard(state, val); |
+ if (!uniqueness_guard.is_valid()) |
return base::Value::CreateNullValue().release(); |
std::unique_ptr<v8::Context::Scope> scope; |