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

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

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

Powered by Google App Engine
This is Rietveld 408576698