Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Side by Side Diff: trunk/src/content/renderer/v8_value_converter_impl.cc

Issue 16511004: Revert 205184 "Revert 204057 "Recurse to a maximum depth of 10 i..." (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/v8_value_converter_impl.h" 5 #include "content/renderer/v8_value_converter_impl.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/float_util.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
11 #include "base/values.h" 12 #include "base/values.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBuffer.h" 13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBuffer.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBufferView.h" 14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBufferView.h"
14 #include "v8/include/v8.h" 15 #include "v8/include/v8.h"
15 16
16 namespace content { 17 namespace content {
17 18
19 namespace {
20 const int kMaxRecursionDepth = 10;
21 }
22
23 // The state of a call to FromV8Value.
24 class V8ValueConverterImpl::FromV8ValueState {
25 public:
26 // Level scope which updates the current depth of some FromV8ValueState.
27 class Level {
28 public:
29 explicit Level(FromV8ValueState* state) : state_(state) {
30 state_->max_recursion_depth_--;
31 }
32 ~Level() {
33 state_->max_recursion_depth_++;
34 }
35
36 private:
37 FromV8ValueState* state_;
38 };
39
40 explicit FromV8ValueState(bool avoid_identity_hash_for_testing)
41 : max_recursion_depth_(kMaxRecursionDepth),
42 avoid_identity_hash_for_testing_(avoid_identity_hash_for_testing) {}
43
44 // If |handle| is not in |unique_map_|, then add it to |unique_map_| and
45 // return true.
46 //
47 // Otherwise do nothing and return false. Here "A is unique" means that no
48 // other handle B in the map points to the same object as A. Note that A can
49 // be unique even if there already is another handle with the same identity
50 // hash (key) in the map, because two objects can have the same hash.
51 bool UpdateAndCheckUniqueness(v8::Handle<v8::Object> handle) {
52 typedef HashToHandleMap::const_iterator Iterator;
53 int hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash();
54 // We only compare using == with handles to objects with the same identity
55 // hash. Different hash obviously means different objects, but two objects
56 // in a couple of thousands could have the same identity hash.
57 std::pair<Iterator, Iterator> range = unique_map_.equal_range(hash);
58 for (Iterator it = range.first; it != range.second; ++it) {
59 // Operator == for handles actually compares the underlying objects.
60 if (it->second == handle)
61 return false;
62 }
63 unique_map_.insert(std::make_pair(hash, handle));
64 return true;
65 }
66
67 bool HasReachedMaxRecursionDepth() {
68 return max_recursion_depth_ < 0;
69 }
70
71 private:
72 typedef std::multimap<int, v8::Handle<v8::Object> > HashToHandleMap;
73 HashToHandleMap unique_map_;
74
75 int max_recursion_depth_;
76
77 bool avoid_identity_hash_for_testing_;
78 };
79
18 V8ValueConverter* V8ValueConverter::create() { 80 V8ValueConverter* V8ValueConverter::create() {
19 return new V8ValueConverterImpl(); 81 return new V8ValueConverterImpl();
20 } 82 }
21 83
22 V8ValueConverterImpl::V8ValueConverterImpl() 84 V8ValueConverterImpl::V8ValueConverterImpl()
23 : date_allowed_(false), 85 : date_allowed_(false),
24 reg_exp_allowed_(false), 86 reg_exp_allowed_(false),
25 function_allowed_(false), 87 function_allowed_(false),
26 strip_null_from_objects_(false), 88 strip_null_from_objects_(false),
27 avoid_identity_hash_for_testing_(false) {} 89 avoid_identity_hash_for_testing_(false) {}
(...skipping 19 matching lines...) Expand all
47 v8::Context::Scope context_scope(context); 109 v8::Context::Scope context_scope(context);
48 v8::HandleScope handle_scope; 110 v8::HandleScope handle_scope;
49 return handle_scope.Close(ToV8ValueImpl(value)); 111 return handle_scope.Close(ToV8ValueImpl(value));
50 } 112 }
51 113
52 Value* V8ValueConverterImpl::FromV8Value( 114 Value* V8ValueConverterImpl::FromV8Value(
53 v8::Handle<v8::Value> val, 115 v8::Handle<v8::Value> val,
54 v8::Handle<v8::Context> context) const { 116 v8::Handle<v8::Context> context) const {
55 v8::Context::Scope context_scope(context); 117 v8::Context::Scope context_scope(context);
56 v8::HandleScope handle_scope; 118 v8::HandleScope handle_scope;
57 HashToHandleMap unique_map; 119 FromV8ValueState state(avoid_identity_hash_for_testing_);
58 return FromV8ValueImpl(val, &unique_map); 120 return FromV8ValueImpl(val, &state);
59 } 121 }
60 122
61 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( 123 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl(
62 const base::Value* value) const { 124 const base::Value* value) const {
63 CHECK(value); 125 CHECK(value);
64 switch (value->GetType()) { 126 switch (value->GetType()) {
65 case base::Value::TYPE_NULL: 127 case base::Value::TYPE_NULL:
66 return v8::Null(); 128 return v8::Null();
67 129
68 case base::Value::TYPE_BOOLEAN: { 130 case base::Value::TYPE_BOOLEAN: {
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 } 208 }
147 209
148 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer( 210 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer(
149 const base::BinaryValue* value) const { 211 const base::BinaryValue* value) const {
150 WebKit::WebArrayBuffer buffer = 212 WebKit::WebArrayBuffer buffer =
151 WebKit::WebArrayBuffer::create(value->GetSize(), 1); 213 WebKit::WebArrayBuffer::create(value->GetSize(), 1);
152 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); 214 memcpy(buffer.data(), value->GetBuffer(), value->GetSize());
153 return buffer.toV8Value(); 215 return buffer.toV8Value();
154 } 216 }
155 217
156 Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val, 218 Value* V8ValueConverterImpl::FromV8ValueImpl(
157 HashToHandleMap* unique_map) const { 219 v8::Handle<v8::Value> val,
220 FromV8ValueState* state) const {
158 CHECK(!val.IsEmpty()); 221 CHECK(!val.IsEmpty());
159 222
223 FromV8ValueState::Level state_level(state);
224 if (state->HasReachedMaxRecursionDepth())
225 return NULL;
226
160 if (val->IsNull()) 227 if (val->IsNull())
161 return base::Value::CreateNullValue(); 228 return base::Value::CreateNullValue();
162 229
163 if (val->IsBoolean()) 230 if (val->IsBoolean())
164 return new base::FundamentalValue(val->ToBoolean()->Value()); 231 return new base::FundamentalValue(val->ToBoolean()->Value());
165 232
166 if (val->IsInt32()) 233 if (val->IsInt32())
167 return new base::FundamentalValue(val->ToInt32()->Value()); 234 return new base::FundamentalValue(val->ToInt32()->Value());
168 235
169 if (val->IsNumber()) 236 if (val->IsNumber()) {
170 return new base::FundamentalValue(val->ToNumber()->Value()); 237 double val_as_double = val->ToNumber()->Value();
238 if (!base::IsFinite(val_as_double))
239 return NULL;
240 return new base::FundamentalValue(val_as_double);
241 }
171 242
172 if (val->IsString()) { 243 if (val->IsString()) {
173 v8::String::Utf8Value utf8(val->ToString()); 244 v8::String::Utf8Value utf8(val->ToString());
174 return new base::StringValue(std::string(*utf8, utf8.length())); 245 return new base::StringValue(std::string(*utf8, utf8.length()));
175 } 246 }
176 247
177 if (val->IsUndefined()) 248 if (val->IsUndefined())
178 // JSON.stringify ignores undefined. 249 // JSON.stringify ignores undefined.
179 return NULL; 250 return NULL;
180 251
181 if (val->IsDate()) { 252 if (val->IsDate()) {
182 if (!date_allowed_) 253 if (!date_allowed_)
183 // JSON.stringify would convert this to a string, but an object is more 254 // JSON.stringify would convert this to a string, but an object is more
184 // consistent within this class. 255 // consistent within this class.
185 return FromV8Object(val->ToObject(), unique_map); 256 return FromV8Object(val->ToObject(), state);
186 v8::Date* date = v8::Date::Cast(*val); 257 v8::Date* date = v8::Date::Cast(*val);
187 return new base::FundamentalValue(date->NumberValue() / 1000.0); 258 return new base::FundamentalValue(date->NumberValue() / 1000.0);
188 } 259 }
189 260
190 if (val->IsRegExp()) { 261 if (val->IsRegExp()) {
191 if (!reg_exp_allowed_) 262 if (!reg_exp_allowed_)
192 // JSON.stringify converts to an object. 263 // JSON.stringify converts to an object.
193 return FromV8Object(val->ToObject(), unique_map); 264 return FromV8Object(val->ToObject(), state);
194 return new base::StringValue(*v8::String::Utf8Value(val->ToString())); 265 return new base::StringValue(*v8::String::Utf8Value(val->ToString()));
195 } 266 }
196 267
197 // v8::Value doesn't have a ToArray() method for some reason. 268 // v8::Value doesn't have a ToArray() method for some reason.
198 if (val->IsArray()) 269 if (val->IsArray())
199 return FromV8Array(val.As<v8::Array>(), unique_map); 270 return FromV8Array(val.As<v8::Array>(), state);
200 271
201 if (val->IsFunction()) { 272 if (val->IsFunction()) {
202 if (!function_allowed_) 273 if (!function_allowed_)
203 // JSON.stringify refuses to convert function(){}. 274 // JSON.stringify refuses to convert function(){}.
204 return NULL; 275 return NULL;
205 return FromV8Object(val->ToObject(), unique_map); 276 return FromV8Object(val->ToObject(), state);
206 } 277 }
207 278
208 if (val->IsObject()) { 279 if (val->IsObject()) {
209 base::BinaryValue* binary_value = FromV8Buffer(val); 280 base::BinaryValue* binary_value = FromV8Buffer(val);
210 if (binary_value) { 281 if (binary_value) {
211 return binary_value; 282 return binary_value;
212 } else { 283 } else {
213 return FromV8Object(val->ToObject(), unique_map); 284 return FromV8Object(val->ToObject(), state);
214 } 285 }
215 } 286 }
216 287
217 LOG(ERROR) << "Unexpected v8 value type encountered."; 288 LOG(ERROR) << "Unexpected v8 value type encountered.";
218 return NULL; 289 return NULL;
219 } 290 }
220 291
221 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val, 292 Value* V8ValueConverterImpl::FromV8Array(
222 HashToHandleMap* unique_map) const { 293 v8::Handle<v8::Array> val,
223 if (!UpdateAndCheckUniqueness(unique_map, val)) 294 FromV8ValueState* state) const {
295 if (!state->UpdateAndCheckUniqueness(val))
224 return base::Value::CreateNullValue(); 296 return base::Value::CreateNullValue();
225 297
226 scoped_ptr<v8::Context::Scope> scope; 298 scoped_ptr<v8::Context::Scope> scope;
227 // If val was created in a different context than our current one, change to 299 // If val was created in a different context than our current one, change to
228 // that context, but change back after val is converted. 300 // that context, but change back after val is converted.
229 if (!val->CreationContext().IsEmpty() && 301 if (!val->CreationContext().IsEmpty() &&
230 val->CreationContext() != v8::Context::GetCurrent()) 302 val->CreationContext() != v8::Context::GetCurrent())
231 scope.reset(new v8::Context::Scope(val->CreationContext())); 303 scope.reset(new v8::Context::Scope(val->CreationContext()));
232 304
233 base::ListValue* result = new base::ListValue(); 305 base::ListValue* result = new base::ListValue();
234 306
235 // Only fields with integer keys are carried over to the ListValue. 307 // Only fields with integer keys are carried over to the ListValue.
236 for (uint32 i = 0; i < val->Length(); ++i) { 308 for (uint32 i = 0; i < val->Length(); ++i) {
237 v8::TryCatch try_catch; 309 v8::TryCatch try_catch;
238 v8::Handle<v8::Value> child_v8 = val->Get(i); 310 v8::Handle<v8::Value> child_v8 = val->Get(i);
239 if (try_catch.HasCaught()) { 311 if (try_catch.HasCaught()) {
240 LOG(ERROR) << "Getter for index " << i << " threw an exception."; 312 LOG(ERROR) << "Getter for index " << i << " threw an exception.";
241 child_v8 = v8::Null(); 313 child_v8 = v8::Null();
242 } 314 }
243 315
244 if (!val->HasRealIndexedProperty(i)) 316 if (!val->HasRealIndexedProperty(i))
245 continue; 317 continue;
246 318
247 base::Value* child = FromV8ValueImpl(child_v8, unique_map); 319 base::Value* child = FromV8ValueImpl(child_v8, state);
248 if (child) 320 if (child)
249 result->Append(child); 321 result->Append(child);
250 else 322 else
251 // JSON.stringify puts null in places where values don't serialize, for 323 // JSON.stringify puts null in places where values don't serialize, for
252 // example undefined and functions. Emulate that behavior. 324 // example undefined and functions. Emulate that behavior.
253 result->Append(base::Value::CreateNullValue()); 325 result->Append(base::Value::CreateNullValue());
254 } 326 }
255 return result; 327 return result;
256 } 328 }
257 329
(...skipping 17 matching lines...) Expand all
275 } 347 }
276 348
277 if (data) 349 if (data)
278 return base::BinaryValue::CreateWithCopiedBuffer(data, length); 350 return base::BinaryValue::CreateWithCopiedBuffer(data, length);
279 else 351 else
280 return NULL; 352 return NULL;
281 } 353 }
282 354
283 Value* V8ValueConverterImpl::FromV8Object( 355 Value* V8ValueConverterImpl::FromV8Object(
284 v8::Handle<v8::Object> val, 356 v8::Handle<v8::Object> val,
285 HashToHandleMap* unique_map) const { 357 FromV8ValueState* state) const {
286 if (!UpdateAndCheckUniqueness(unique_map, val)) 358 if (!state->UpdateAndCheckUniqueness(val))
287 return base::Value::CreateNullValue(); 359 return base::Value::CreateNullValue();
288 scoped_ptr<v8::Context::Scope> scope; 360 scoped_ptr<v8::Context::Scope> scope;
289 // If val was created in a different context than our current one, change to 361 // If val was created in a different context than our current one, change to
290 // that context, but change back after val is converted. 362 // that context, but change back after val is converted.
291 if (!val->CreationContext().IsEmpty() && 363 if (!val->CreationContext().IsEmpty() &&
292 val->CreationContext() != v8::Context::GetCurrent()) 364 val->CreationContext() != v8::Context::GetCurrent())
293 scope.reset(new v8::Context::Scope(val->CreationContext())); 365 scope.reset(new v8::Context::Scope(val->CreationContext()));
294 366
295 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); 367 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
296 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames()); 368 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames());
297 369
298 for (uint32 i = 0; i < property_names->Length(); ++i) { 370 for (uint32 i = 0; i < property_names->Length(); ++i) {
299 v8::Handle<v8::Value> key(property_names->Get(i)); 371 v8::Handle<v8::Value> key(property_names->Get(i));
300 372
301 // Extend this test to cover more types as necessary and if sensible. 373 // Extend this test to cover more types as necessary and if sensible.
302 if (!key->IsString() && 374 if (!key->IsString() &&
303 !key->IsNumber()) { 375 !key->IsNumber()) {
304 NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" " 376 NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" "
305 "is neither a string nor a number"; 377 "is neither a string nor a number";
306 continue; 378 continue;
307 } 379 }
308 380
309 // Skip all callbacks: crbug.com/139933
310 if (val->HasRealNamedCallbackProperty(key->ToString()))
311 continue;
312
313 v8::String::Utf8Value name_utf8(key->ToString()); 381 v8::String::Utf8Value name_utf8(key->ToString());
314 382
315 v8::TryCatch try_catch; 383 v8::TryCatch try_catch;
316 v8::Handle<v8::Value> child_v8 = val->Get(key); 384 v8::Handle<v8::Value> child_v8 = val->Get(key);
317 385
318 if (try_catch.HasCaught()) { 386 if (try_catch.HasCaught()) {
319 LOG(ERROR) << "Getter for property " << *name_utf8 387 LOG(ERROR) << "Getter for property " << *name_utf8
320 << " threw an exception."; 388 << " threw an exception.";
321 child_v8 = v8::Null(); 389 child_v8 = v8::Null();
322 } 390 }
323 391
324 scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, unique_map)); 392 scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, state));
325 if (!child) 393 if (!child)
326 // JSON.stringify skips properties whose values don't serialize, for 394 // JSON.stringify skips properties whose values don't serialize, for
327 // example undefined and functions. Emulate that behavior. 395 // example undefined and functions. Emulate that behavior.
328 continue; 396 continue;
329 397
330 // Strip null if asked (and since undefined is turned into null, undefined 398 // Strip null if asked (and since undefined is turned into null, undefined
331 // too). The use case for supporting this is JSON-schema support, 399 // too). The use case for supporting this is JSON-schema support,
332 // specifically for extensions, where "optional" JSON properties may be 400 // specifically for extensions, where "optional" JSON properties may be
333 // represented as null, yet due to buggy legacy code elsewhere isn't 401 // represented as null, yet due to buggy legacy code elsewhere isn't
334 // treated as such (potentially causing crashes). For example, the 402 // treated as such (potentially causing crashes). For example, the
(...skipping 15 matching lines...) Expand all
350 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL)) 418 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL))
351 continue; 419 continue;
352 420
353 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), 421 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()),
354 child.release()); 422 child.release());
355 } 423 }
356 424
357 return result.release(); 425 return result.release();
358 } 426 }
359 427
360 bool V8ValueConverterImpl::UpdateAndCheckUniqueness(
361 HashToHandleMap* map,
362 v8::Handle<v8::Object> handle) const {
363 typedef HashToHandleMap::const_iterator Iterator;
364
365 int hash = avoid_identity_hash_for_testing_ ? 0 : handle->GetIdentityHash();
366 // We only compare using == with handles to objects with the same identity
367 // hash. Different hash obviously means different objects, but two objects in
368 // a couple of thousands could have the same identity hash.
369 std::pair<Iterator, Iterator> range = map->equal_range(hash);
370 for (Iterator it = range.first; it != range.second; ++it) {
371 // Operator == for handles actually compares the underlying objects.
372 if (it->second == handle)
373 return false;
374 }
375
376 map->insert(std::pair<int, v8::Handle<v8::Object> >(hash, handle));
377 return true;
378 }
379
380 } // namespace content 428 } // namespace content
OLDNEW
« no previous file with comments | « trunk/src/content/renderer/v8_value_converter_impl.h ('k') | trunk/src/content/renderer/v8_value_converter_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698