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

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

Issue 16733002: Revert 204057 "Recurse to a maximum depth of 10 in v8_value_conv..." (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"
10 #include "base/logging.h" 9 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
12 #include "base/values.h" 11 #include "base/values.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBuffer.h" 12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBuffer.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBufferView.h" 13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebArrayBufferView.h"
15 #include "v8/include/v8.h" 14 #include "v8/include/v8.h"
16 15
17 namespace content { 16 namespace content {
18 17
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
80 V8ValueConverter* V8ValueConverter::create() { 18 V8ValueConverter* V8ValueConverter::create() {
81 return new V8ValueConverterImpl(); 19 return new V8ValueConverterImpl();
82 } 20 }
83 21
84 V8ValueConverterImpl::V8ValueConverterImpl() 22 V8ValueConverterImpl::V8ValueConverterImpl()
85 : date_allowed_(false), 23 : date_allowed_(false),
86 reg_exp_allowed_(false), 24 reg_exp_allowed_(false),
87 function_allowed_(false), 25 function_allowed_(false),
88 strip_null_from_objects_(false), 26 strip_null_from_objects_(false),
89 avoid_identity_hash_for_testing_(false) {} 27 avoid_identity_hash_for_testing_(false) {}
(...skipping 19 matching lines...) Expand all
109 v8::Context::Scope context_scope(context); 47 v8::Context::Scope context_scope(context);
110 v8::HandleScope handle_scope; 48 v8::HandleScope handle_scope;
111 return handle_scope.Close(ToV8ValueImpl(value)); 49 return handle_scope.Close(ToV8ValueImpl(value));
112 } 50 }
113 51
114 Value* V8ValueConverterImpl::FromV8Value( 52 Value* V8ValueConverterImpl::FromV8Value(
115 v8::Handle<v8::Value> val, 53 v8::Handle<v8::Value> val,
116 v8::Handle<v8::Context> context) const { 54 v8::Handle<v8::Context> context) const {
117 v8::Context::Scope context_scope(context); 55 v8::Context::Scope context_scope(context);
118 v8::HandleScope handle_scope; 56 v8::HandleScope handle_scope;
119 FromV8ValueState state(avoid_identity_hash_for_testing_); 57 HashToHandleMap unique_map;
120 return FromV8ValueImpl(val, &state); 58 return FromV8ValueImpl(val, &unique_map);
121 } 59 }
122 60
123 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( 61 v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl(
124 const base::Value* value) const { 62 const base::Value* value) const {
125 CHECK(value); 63 CHECK(value);
126 switch (value->GetType()) { 64 switch (value->GetType()) {
127 case base::Value::TYPE_NULL: 65 case base::Value::TYPE_NULL:
128 return v8::Null(); 66 return v8::Null();
129 67
130 case base::Value::TYPE_BOOLEAN: { 68 case base::Value::TYPE_BOOLEAN: {
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 } 146 }
209 147
210 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer( 148 v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer(
211 const base::BinaryValue* value) const { 149 const base::BinaryValue* value) const {
212 WebKit::WebArrayBuffer buffer = 150 WebKit::WebArrayBuffer buffer =
213 WebKit::WebArrayBuffer::create(value->GetSize(), 1); 151 WebKit::WebArrayBuffer::create(value->GetSize(), 1);
214 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); 152 memcpy(buffer.data(), value->GetBuffer(), value->GetSize());
215 return buffer.toV8Value(); 153 return buffer.toV8Value();
216 } 154 }
217 155
218 Value* V8ValueConverterImpl::FromV8ValueImpl( 156 Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val,
219 v8::Handle<v8::Value> val, 157 HashToHandleMap* unique_map) const {
220 FromV8ValueState* state) const {
221 CHECK(!val.IsEmpty()); 158 CHECK(!val.IsEmpty());
222 159
223 FromV8ValueState::Level state_level(state);
224 if (state->HasReachedMaxRecursionDepth())
225 return NULL;
226
227 if (val->IsNull()) 160 if (val->IsNull())
228 return base::Value::CreateNullValue(); 161 return base::Value::CreateNullValue();
229 162
230 if (val->IsBoolean()) 163 if (val->IsBoolean())
231 return new base::FundamentalValue(val->ToBoolean()->Value()); 164 return new base::FundamentalValue(val->ToBoolean()->Value());
232 165
233 if (val->IsInt32()) 166 if (val->IsInt32())
234 return new base::FundamentalValue(val->ToInt32()->Value()); 167 return new base::FundamentalValue(val->ToInt32()->Value());
235 168
236 if (val->IsNumber()) { 169 if (val->IsNumber())
237 double val_as_double = val->ToNumber()->Value(); 170 return new base::FundamentalValue(val->ToNumber()->Value());
238 if (!base::IsFinite(val_as_double))
239 return NULL;
240 return new base::FundamentalValue(val_as_double);
241 }
242 171
243 if (val->IsString()) { 172 if (val->IsString()) {
244 v8::String::Utf8Value utf8(val->ToString()); 173 v8::String::Utf8Value utf8(val->ToString());
245 return new base::StringValue(std::string(*utf8, utf8.length())); 174 return new base::StringValue(std::string(*utf8, utf8.length()));
246 } 175 }
247 176
248 if (val->IsUndefined()) 177 if (val->IsUndefined())
249 // JSON.stringify ignores undefined. 178 // JSON.stringify ignores undefined.
250 return NULL; 179 return NULL;
251 180
252 if (val->IsDate()) { 181 if (val->IsDate()) {
253 if (!date_allowed_) 182 if (!date_allowed_)
254 // JSON.stringify would convert this to a string, but an object is more 183 // JSON.stringify would convert this to a string, but an object is more
255 // consistent within this class. 184 // consistent within this class.
256 return FromV8Object(val->ToObject(), state); 185 return FromV8Object(val->ToObject(), unique_map);
257 v8::Date* date = v8::Date::Cast(*val); 186 v8::Date* date = v8::Date::Cast(*val);
258 return new base::FundamentalValue(date->NumberValue() / 1000.0); 187 return new base::FundamentalValue(date->NumberValue() / 1000.0);
259 } 188 }
260 189
261 if (val->IsRegExp()) { 190 if (val->IsRegExp()) {
262 if (!reg_exp_allowed_) 191 if (!reg_exp_allowed_)
263 // JSON.stringify converts to an object. 192 // JSON.stringify converts to an object.
264 return FromV8Object(val->ToObject(), state); 193 return FromV8Object(val->ToObject(), unique_map);
265 return new base::StringValue(*v8::String::Utf8Value(val->ToString())); 194 return new base::StringValue(*v8::String::Utf8Value(val->ToString()));
266 } 195 }
267 196
268 // v8::Value doesn't have a ToArray() method for some reason. 197 // v8::Value doesn't have a ToArray() method for some reason.
269 if (val->IsArray()) 198 if (val->IsArray())
270 return FromV8Array(val.As<v8::Array>(), state); 199 return FromV8Array(val.As<v8::Array>(), unique_map);
271 200
272 if (val->IsFunction()) { 201 if (val->IsFunction()) {
273 if (!function_allowed_) 202 if (!function_allowed_)
274 // JSON.stringify refuses to convert function(){}. 203 // JSON.stringify refuses to convert function(){}.
275 return NULL; 204 return NULL;
276 return FromV8Object(val->ToObject(), state); 205 return FromV8Object(val->ToObject(), unique_map);
277 } 206 }
278 207
279 if (val->IsObject()) { 208 if (val->IsObject()) {
280 base::BinaryValue* binary_value = FromV8Buffer(val); 209 base::BinaryValue* binary_value = FromV8Buffer(val);
281 if (binary_value) { 210 if (binary_value) {
282 return binary_value; 211 return binary_value;
283 } else { 212 } else {
284 return FromV8Object(val->ToObject(), state); 213 return FromV8Object(val->ToObject(), unique_map);
285 } 214 }
286 } 215 }
287 216
288 LOG(ERROR) << "Unexpected v8 value type encountered."; 217 LOG(ERROR) << "Unexpected v8 value type encountered.";
289 return NULL; 218 return NULL;
290 } 219 }
291 220
292 Value* V8ValueConverterImpl::FromV8Array( 221 Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val,
293 v8::Handle<v8::Array> val, 222 HashToHandleMap* unique_map) const {
294 FromV8ValueState* state) const { 223 if (!UpdateAndCheckUniqueness(unique_map, val))
295 if (!state->UpdateAndCheckUniqueness(val))
296 return base::Value::CreateNullValue(); 224 return base::Value::CreateNullValue();
297 225
298 scoped_ptr<v8::Context::Scope> scope; 226 scoped_ptr<v8::Context::Scope> scope;
299 // If val was created in a different context than our current one, change to 227 // If val was created in a different context than our current one, change to
300 // that context, but change back after val is converted. 228 // that context, but change back after val is converted.
301 if (!val->CreationContext().IsEmpty() && 229 if (!val->CreationContext().IsEmpty() &&
302 val->CreationContext() != v8::Context::GetCurrent()) 230 val->CreationContext() != v8::Context::GetCurrent())
303 scope.reset(new v8::Context::Scope(val->CreationContext())); 231 scope.reset(new v8::Context::Scope(val->CreationContext()));
304 232
305 base::ListValue* result = new base::ListValue(); 233 base::ListValue* result = new base::ListValue();
306 234
307 // Only fields with integer keys are carried over to the ListValue. 235 // Only fields with integer keys are carried over to the ListValue.
308 for (uint32 i = 0; i < val->Length(); ++i) { 236 for (uint32 i = 0; i < val->Length(); ++i) {
309 v8::TryCatch try_catch; 237 v8::TryCatch try_catch;
310 v8::Handle<v8::Value> child_v8 = val->Get(i); 238 v8::Handle<v8::Value> child_v8 = val->Get(i);
311 if (try_catch.HasCaught()) { 239 if (try_catch.HasCaught()) {
312 LOG(ERROR) << "Getter for index " << i << " threw an exception."; 240 LOG(ERROR) << "Getter for index " << i << " threw an exception.";
313 child_v8 = v8::Null(); 241 child_v8 = v8::Null();
314 } 242 }
315 243
316 if (!val->HasRealIndexedProperty(i)) 244 if (!val->HasRealIndexedProperty(i))
317 continue; 245 continue;
318 246
319 base::Value* child = FromV8ValueImpl(child_v8, state); 247 base::Value* child = FromV8ValueImpl(child_v8, unique_map);
320 if (child) 248 if (child)
321 result->Append(child); 249 result->Append(child);
322 else 250 else
323 // JSON.stringify puts null in places where values don't serialize, for 251 // JSON.stringify puts null in places where values don't serialize, for
324 // example undefined and functions. Emulate that behavior. 252 // example undefined and functions. Emulate that behavior.
325 result->Append(base::Value::CreateNullValue()); 253 result->Append(base::Value::CreateNullValue());
326 } 254 }
327 return result; 255 return result;
328 } 256 }
329 257
(...skipping 17 matching lines...) Expand all
347 } 275 }
348 276
349 if (data) 277 if (data)
350 return base::BinaryValue::CreateWithCopiedBuffer(data, length); 278 return base::BinaryValue::CreateWithCopiedBuffer(data, length);
351 else 279 else
352 return NULL; 280 return NULL;
353 } 281 }
354 282
355 Value* V8ValueConverterImpl::FromV8Object( 283 Value* V8ValueConverterImpl::FromV8Object(
356 v8::Handle<v8::Object> val, 284 v8::Handle<v8::Object> val,
357 FromV8ValueState* state) const { 285 HashToHandleMap* unique_map) const {
358 if (!state->UpdateAndCheckUniqueness(val)) 286 if (!UpdateAndCheckUniqueness(unique_map, val))
359 return base::Value::CreateNullValue(); 287 return base::Value::CreateNullValue();
360 scoped_ptr<v8::Context::Scope> scope; 288 scoped_ptr<v8::Context::Scope> scope;
361 // If val was created in a different context than our current one, change to 289 // If val was created in a different context than our current one, change to
362 // that context, but change back after val is converted. 290 // that context, but change back after val is converted.
363 if (!val->CreationContext().IsEmpty() && 291 if (!val->CreationContext().IsEmpty() &&
364 val->CreationContext() != v8::Context::GetCurrent()) 292 val->CreationContext() != v8::Context::GetCurrent())
365 scope.reset(new v8::Context::Scope(val->CreationContext())); 293 scope.reset(new v8::Context::Scope(val->CreationContext()));
366 294
367 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); 295 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
368 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames()); 296 v8::Handle<v8::Array> property_names(val->GetOwnPropertyNames());
369 297
370 for (uint32 i = 0; i < property_names->Length(); ++i) { 298 for (uint32 i = 0; i < property_names->Length(); ++i) {
371 v8::Handle<v8::Value> key(property_names->Get(i)); 299 v8::Handle<v8::Value> key(property_names->Get(i));
372 300
373 // Extend this test to cover more types as necessary and if sensible. 301 // Extend this test to cover more types as necessary and if sensible.
374 if (!key->IsString() && 302 if (!key->IsString() &&
375 !key->IsNumber()) { 303 !key->IsNumber()) {
376 NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" " 304 NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" "
377 "is neither a string nor a number"; 305 "is neither a string nor a number";
378 continue; 306 continue;
379 } 307 }
380 308
309 // Skip all callbacks: crbug.com/139933
310 if (val->HasRealNamedCallbackProperty(key->ToString()))
311 continue;
312
381 v8::String::Utf8Value name_utf8(key->ToString()); 313 v8::String::Utf8Value name_utf8(key->ToString());
382 314
383 v8::TryCatch try_catch; 315 v8::TryCatch try_catch;
384 v8::Handle<v8::Value> child_v8 = val->Get(key); 316 v8::Handle<v8::Value> child_v8 = val->Get(key);
385 317
386 if (try_catch.HasCaught()) { 318 if (try_catch.HasCaught()) {
387 LOG(ERROR) << "Getter for property " << *name_utf8 319 LOG(ERROR) << "Getter for property " << *name_utf8
388 << " threw an exception."; 320 << " threw an exception.";
389 child_v8 = v8::Null(); 321 child_v8 = v8::Null();
390 } 322 }
391 323
392 scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, state)); 324 scoped_ptr<base::Value> child(FromV8ValueImpl(child_v8, unique_map));
393 if (!child) 325 if (!child)
394 // JSON.stringify skips properties whose values don't serialize, for 326 // JSON.stringify skips properties whose values don't serialize, for
395 // example undefined and functions. Emulate that behavior. 327 // example undefined and functions. Emulate that behavior.
396 continue; 328 continue;
397 329
398 // Strip null if asked (and since undefined is turned into null, undefined 330 // Strip null if asked (and since undefined is turned into null, undefined
399 // too). The use case for supporting this is JSON-schema support, 331 // too). The use case for supporting this is JSON-schema support,
400 // specifically for extensions, where "optional" JSON properties may be 332 // specifically for extensions, where "optional" JSON properties may be
401 // represented as null, yet due to buggy legacy code elsewhere isn't 333 // represented as null, yet due to buggy legacy code elsewhere isn't
402 // treated as such (potentially causing crashes). For example, the 334 // treated as such (potentially causing crashes). For example, the
(...skipping 15 matching lines...) Expand all
418 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL)) 350 if (strip_null_from_objects_ && child->IsType(Value::TYPE_NULL))
419 continue; 351 continue;
420 352
421 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), 353 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()),
422 child.release()); 354 child.release());
423 } 355 }
424 356
425 return result.release(); 357 return result.release();
426 } 358 }
427 359
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
428 } // namespace content 380 } // 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