diff options
author | kalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-10 14:20:41 +0000 |
---|---|---|
committer | kalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-10 14:20:41 +0000 |
commit | 195487fc27da171fc6a7420991d947033d33ebf0 (patch) | |
tree | c6628640bfab88fa67553e763190b47cc8dfe83a /content/renderer/v8_value_converter_impl.cc | |
parent | 5a730cc079afbaf81f59c529da08d90c75210c13 (diff) | |
download | chromium_src-195487fc27da171fc6a7420991d947033d33ebf0.zip chromium_src-195487fc27da171fc6a7420991d947033d33ebf0.tar.gz chromium_src-195487fc27da171fc6a7420991d947033d33ebf0.tar.bz2 |
Revert 205184 "Revert 204057 "Recurse to a maximum depth of 10 i..."
> Revert 204057 "Recurse to a maximum depth of 10 in v8_value_conv..."
>
> The commit caused crbug.com/248019.
>
> > Recurse to a maximum depth of 10 in v8_value_converter_impl.cc. There are
> > objects that get passed in (canonically <input> elements apparently) which
> > recurse infinitely (as opposed to having a self-referential loop).
> >
> > The previous solution to this problem (r150035) was to disable getters, which
> > apparently were the main cause, but this is no longer appropriate - we now use
> > this mechanism for all extension messaging, and this has become a problem (see
> > bug 246213).
> >
> > TBR=jamesr@chromium.org, mpcomplete@chromium.org
> >
> > BUG=246213,139933
> >
> > Review URL: https://codereview.chromium.org/16295013
>
> TBR=kalman@chromium.org
>
> Review URL: https://codereview.chromium.org/16733002
TBR=marja@chromium.org
Review URL: https://codereview.chromium.org/16511004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@205209 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer/v8_value_converter_impl.cc')
-rw-r--r-- | content/renderer/v8_value_converter_impl.cc | 132 |
1 files changed, 90 insertions, 42 deletions
diff --git a/content/renderer/v8_value_converter_impl.cc b/content/renderer/v8_value_converter_impl.cc index e8b2563..2f91371 100644 --- a/content/renderer/v8_value_converter_impl.cc +++ b/content/renderer/v8_value_converter_impl.cc @@ -6,6 +6,7 @@ #include <string> +#include "base/float_util.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/values.h" @@ -15,6 +16,67 @@ namespace content { +namespace { +const int kMaxRecursionDepth = 10; +} + +// The state of a call to FromV8Value. +class V8ValueConverterImpl::FromV8ValueState { + public: + // Level scope which updates the current depth of some FromV8ValueState. + class Level { + public: + explicit Level(FromV8ValueState* state) : state_(state) { + state_->max_recursion_depth_--; + } + ~Level() { + state_->max_recursion_depth_++; + } + + private: + FromV8ValueState* state_; + }; + + explicit FromV8ValueState(bool avoid_identity_hash_for_testing) + : max_recursion_depth_(kMaxRecursionDepth), + avoid_identity_hash_for_testing_(avoid_identity_hash_for_testing) {} + + // If |handle| is not in |unique_map_|, then add it to |unique_map_| and + // return true. + // + // Otherwise do nothing and return false. Here "A is unique" means that no + // 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::Handle<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; + } + unique_map_.insert(std::make_pair(hash, handle)); + return true; + } + + bool HasReachedMaxRecursionDepth() { + return max_recursion_depth_ < 0; + } + + private: + typedef std::multimap<int, v8::Handle<v8::Object> > HashToHandleMap; + HashToHandleMap unique_map_; + + int max_recursion_depth_; + + bool avoid_identity_hash_for_testing_; +}; + V8ValueConverter* V8ValueConverter::create() { return new V8ValueConverterImpl(); } @@ -54,8 +116,8 @@ Value* V8ValueConverterImpl::FromV8Value( v8::Handle<v8::Context> context) const { v8::Context::Scope context_scope(context); v8::HandleScope handle_scope; - HashToHandleMap unique_map; - return FromV8ValueImpl(val, &unique_map); + FromV8ValueState state(avoid_identity_hash_for_testing_); + return FromV8ValueImpl(val, &state); } v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( @@ -153,10 +215,15 @@ v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer( return buffer.toV8Value(); } -Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, - HashToHandleMap* unique_map) const { +Value* V8ValueConverterImpl::FromV8ValueImpl( + v8::Handle<v8::Value> val, + FromV8ValueState* state) const { CHECK(!val.IsEmpty()); + FromV8ValueState::Level state_level(state); + if (state->HasReachedMaxRecursionDepth()) + return NULL; + if (val->IsNull()) return base::Value::CreateNullValue(); @@ -166,8 +233,12 @@ Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, if (val->IsInt32()) return new base::FundamentalValue(val->ToInt32()->Value()); - if (val->IsNumber()) - return new base::FundamentalValue(val->ToNumber()->Value()); + if (val->IsNumber()) { + double val_as_double = val->ToNumber()->Value(); + if (!base::IsFinite(val_as_double)) + return NULL; + return new base::FundamentalValue(val_as_double); + } if (val->IsString()) { v8::String::Utf8Value utf8(val->ToString()); @@ -182,7 +253,7 @@ Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, if (!date_allowed_) // JSON.stringify would convert this to a string, but an object is more // consistent within this class. - return FromV8Object(val->ToObject(), unique_map); + return FromV8Object(val->ToObject(), state); v8::Date* date = v8::Date::Cast(*val); return new base::FundamentalValue(date->NumberValue() / 1000.0); } @@ -190,19 +261,19 @@ Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, if (val->IsRegExp()) { if (!reg_exp_allowed_) // JSON.stringify converts to an object. - return FromV8Object(val->ToObject(), unique_map); + return FromV8Object(val->ToObject(), state); return new base::StringValue(*v8::String::Utf8Value(val->ToString())); } // v8::Value doesn't have a ToArray() method for some reason. if (val->IsArray()) - return FromV8Array(val.As<v8::Array>(), unique_map); + return FromV8Array(val.As<v8::Array>(), state); if (val->IsFunction()) { if (!function_allowed_) // JSON.stringify refuses to convert function(){}. return NULL; - return FromV8Object(val->ToObject(), unique_map); + return FromV8Object(val->ToObject(), state); } if (val->IsObject()) { @@ -210,7 +281,7 @@ Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, if (binary_value) { return binary_value; } else { - return FromV8Object(val->ToObject(), unique_map); + return FromV8Object(val->ToObject(), state); } } @@ -218,9 +289,10 @@ Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, return NULL; } -Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, - HashToHandleMap* unique_map) const { - if (!UpdateAndCheckUniqueness(unique_map, val)) +Value* V8ValueConverterImpl::FromV8Array( + v8::Handle<v8::Array> val, + FromV8ValueState* state) const { + if (!state->UpdateAndCheckUniqueness(val)) return base::Value::CreateNullValue(); scoped_ptr<v8::Context::Scope> scope; @@ -244,7 +316,7 @@ Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, if (!val->HasRealIndexedProperty(i)) continue; - base::Value* child = FromV8ValueImpl(child_v8, unique_map); + base::Value* child = FromV8ValueImpl(child_v8, state); if (child) result->Append(child); else @@ -282,8 +354,8 @@ base::BinaryValue* V8ValueConverterImpl::FromV8Buffer( Value* V8ValueConverterImpl::FromV8Object( v8::Handle<v8::Object> val, - HashToHandleMap* unique_map) const { - if (!UpdateAndCheckUniqueness(unique_map, val)) + FromV8ValueState* state) const { + if (!state->UpdateAndCheckUniqueness(val)) return base::Value::CreateNullValue(); scoped_ptr<v8::Context::Scope> scope; // If val was created in a different context than our current one, change to @@ -306,10 +378,6 @@ Value* V8ValueConverterImpl::FromV8Object( continue; } - // Skip all callbacks: crbug.com/139933 - if (val->HasRealNamedCallbackProperty(key->ToString())) - continue; - v8::String::Utf8Value name_utf8(key->ToString()); v8::TryCatch try_catch; @@ -321,7 +389,7 @@ Value* V8ValueConverterImpl::FromV8Object( child_v8 = v8::Null(); } - scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, unique_map)); + scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, state)); if (!child) // JSON.stringify skips properties whose values don't serialize, for // example undefined and functions. Emulate that behavior. @@ -357,24 +425,4 @@ Value* V8ValueConverterImpl::FromV8Object( return result.release(); } -bool V8ValueConverterImpl::UpdateAndCheckUniqueness( - HashToHandleMap* map, - v8::Handle<v8::Object> handle) const { - 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 = 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; - } - - map->insert(std::pair<int, v8::Handle<v8::Object> >(hash, handle)); - return true; -} - } // namespace content |