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

Side by Side Diff: src/json-parser.h

Issue 1051833002: Reland: Fix JSON parser Handle leak (previous CL 1041483004) (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix handling of stack overflow Created 5 years, 8 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
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project 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 #ifndef V8_JSON_PARSER_H_ 5 #ifndef V8_JSON_PARSER_H_
6 #define V8_JSON_PARSER_H_ 6 #define V8_JSON_PARSER_H_
7 7
8 #include "src/v8.h" 8 #include "src/v8.h"
9 9
10 #include "src/char-predicates-inl.h" 10 #include "src/char-predicates-inl.h"
11 #include "src/conversions.h" 11 #include "src/conversions.h"
12 #include "src/heap/spaces-inl.h" 12 #include "src/heap/spaces-inl.h"
13 #include "src/messages.h" 13 #include "src/messages.h"
14 #include "src/token.h" 14 #include "src/token.h"
15 15
16 namespace v8 { 16 namespace v8 {
17 namespace internal { 17 namespace internal {
18 18
19 enum ParseElementResult { kElementFound, kElementNotFound, kNullHandle };
20
21
19 // A simple json parser. 22 // A simple json parser.
20 template <bool seq_one_byte> 23 template <bool seq_one_byte>
21 class JsonParser BASE_EMBEDDED { 24 class JsonParser BASE_EMBEDDED {
22 public: 25 public:
23 MUST_USE_RESULT static MaybeHandle<Object> Parse(Handle<String> source) { 26 MUST_USE_RESULT static MaybeHandle<Object> Parse(Handle<String> source) {
24 return JsonParser(source).ParseJson(); 27 return JsonParser(source).ParseJson();
25 } 28 }
26 29
27 static const int kEndOfString = -1; 30 static const int kEndOfString = -1;
28 31
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 Handle<Object> ParseJsonValue(); 151 Handle<Object> ParseJsonValue();
149 152
150 // Parse a JSON object literal (grammar production JSONObject). 153 // Parse a JSON object literal (grammar production JSONObject).
151 // An object literal is a squiggly-braced and comma separated sequence 154 // An object literal is a squiggly-braced and comma separated sequence
152 // (possibly empty) of key/value pairs, where the key is a JSON string 155 // (possibly empty) of key/value pairs, where the key is a JSON string
153 // literal, the value is a JSON value, and the two are separated by a colon. 156 // literal, the value is a JSON value, and the two are separated by a colon.
154 // A JSON array doesn't allow numbers and identifiers as keys, like a 157 // A JSON array doesn't allow numbers and identifiers as keys, like a
155 // JavaScript array. 158 // JavaScript array.
156 Handle<Object> ParseJsonObject(); 159 Handle<Object> ParseJsonObject();
157 160
161 // Helper for ParseJsonObject. Parses the form "123": obj, which is recorded
162 // as an element, not a property.
163 ParseElementResult ParseElement(Handle<JSObject> json_object);
164
158 // Parses a JSON array literal (grammar production JSONArray). An array 165 // Parses a JSON array literal (grammar production JSONArray). An array
159 // literal is a square-bracketed and comma separated sequence (possibly empty) 166 // literal is a square-bracketed and comma separated sequence (possibly empty)
160 // of JSON values. 167 // of JSON values.
161 // A JSON array doesn't allow leaving out values from the sequence, nor does 168 // A JSON array doesn't allow leaving out values from the sequence, nor does
162 // it allow a terminal comma, like a JavaScript array does. 169 // it allow a terminal comma, like a JavaScript array does.
163 Handle<Object> ParseJsonArray(); 170 Handle<Object> ParseJsonArray();
164 171
165 172
166 // Mark that a parsing error has happened at the current token, and 173 // Mark that a parsing error has happened at the current token, and
167 // return a null handle. Primarily for readability. 174 // return a null handle. Primarily for readability.
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 AdvanceGetChar() == 'l') { 299 AdvanceGetChar() == 'l') {
293 AdvanceSkipWhitespace(); 300 AdvanceSkipWhitespace();
294 return factory()->null_value(); 301 return factory()->null_value();
295 } 302 }
296 return ReportUnexpectedCharacter(); 303 return ReportUnexpectedCharacter();
297 } 304 }
298 return ReportUnexpectedCharacter(); 305 return ReportUnexpectedCharacter();
299 } 306 }
300 307
301 308
309 template <bool seq_one_byte>
310 ParseElementResult JsonParser<seq_one_byte>::ParseElement(
311 Handle<JSObject> json_object) {
312 uint32_t index = 0;
313 // Maybe an array index, try to parse it.
314 if (c0_ == '0') {
315 // With a leading zero, the string has to be "0" only to be an index.
316 Advance();
317 } else {
318 do {
319 int d = c0_ - '0';
320 if (index > 429496729U - ((d > 5) ? 1 : 0)) break;
321 index = (index * 10) + d;
322 Advance();
323 } while (IsDecimalDigit(c0_));
324 }
325
326 if (c0_ == '"') {
327 // Successfully parsed index, parse and store element.
328 AdvanceSkipWhitespace();
329
330 if (c0_ == ':') {
331 AdvanceSkipWhitespace();
332 Handle<Object> value = ParseJsonValue();
333 if (!value.is_null()) {
334 JSObject::SetOwnElement(json_object, index, value, SLOPPY).Assert();
335 return kElementFound;
336 } else {
337 return kNullHandle;
338 }
339 }
340 }
341 return kElementNotFound;
342 }
343
302 // Parse a JSON object. Position must be right at '{'. 344 // Parse a JSON object. Position must be right at '{'.
303 template <bool seq_one_byte> 345 template <bool seq_one_byte>
304 Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { 346 Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
305 HandleScope scope(isolate()); 347 HandleScope scope(isolate());
306 Handle<JSObject> json_object = 348 Handle<JSObject> json_object =
307 factory()->NewJSObject(object_constructor(), pretenure_); 349 factory()->NewJSObject(object_constructor(), pretenure_);
308 Handle<Map> map(json_object->map()); 350 Handle<Map> map(json_object->map());
309 int descriptor = 0; 351 int descriptor = 0;
310 ZoneList<Handle<Object> > properties(8, zone()); 352 ZoneList<Handle<Object> > properties(8, zone());
311 DCHECK_EQ(c0_, '{'); 353 DCHECK_EQ(c0_, '{');
312 354
313 bool transitioning = true; 355 bool transitioning = true;
314 356
315 AdvanceSkipWhitespace(); 357 AdvanceSkipWhitespace();
316 if (c0_ != '}') { 358 if (c0_ != '}') {
317 do { 359 do {
318 if (c0_ != '"') return ReportUnexpectedCharacter(); 360 if (c0_ != '"') return ReportUnexpectedCharacter();
319 361
320 int start_position = position_; 362 int start_position = position_;
321 Advance(); 363 Advance();
322 364
323 uint32_t index = 0;
324 if (IsDecimalDigit(c0_)) { 365 if (IsDecimalDigit(c0_)) {
325 // Maybe an array index, try to parse it. 366 ParseElementResult element_result = ParseElement(json_object);
326 if (c0_ == '0') { 367 if (element_result == kNullHandle) return Handle<Object>::null();
327 // With a leading zero, the string has to be "0" only to be an index. 368 if (element_result == kElementFound) continue;
328 Advance();
329 } else {
330 do {
331 int d = c0_ - '0';
332 if (index > 429496729U - ((d > 5) ? 1 : 0)) break;
333 index = (index * 10) + d;
334 Advance();
335 } while (IsDecimalDigit(c0_));
336 }
337
338 if (c0_ == '"') {
339 // Successfully parsed index, parse and store element.
340 AdvanceSkipWhitespace();
341
342 if (c0_ != ':') return ReportUnexpectedCharacter();
343 AdvanceSkipWhitespace();
344 Handle<Object> value = ParseJsonValue();
345 if (value.is_null()) return ReportUnexpectedCharacter();
346
347 JSObject::SetOwnElement(json_object, index, value, SLOPPY).Assert();
348 continue;
349 }
350 // Not an index, fallback to the slow path.
351 } 369 }
370 // Not an index, fallback to the slow path.
352 371
353 position_ = start_position; 372 position_ = start_position;
354 #ifdef DEBUG 373 #ifdef DEBUG
355 c0_ = '"'; 374 c0_ = '"';
356 #endif 375 #endif
357 376
358 Handle<String> key; 377 Handle<String> key;
359 Handle<Object> value; 378 Handle<Object> value;
360 379
361 // Try to follow existing transitions as long as possible. Once we stop 380 // Try to follow existing transitions as long as possible. Once we stop
362 // transitioning, no transition can be found anymore. 381 // transitioning, no transition can be found anymore.
382 DCHECK(transitioning);
383 // First check whether there is a single expected transition. If so, try
384 // to parse it first.
385 bool follow_expected = false;
386 Handle<Map> target;
387 if (seq_one_byte) {
388 key = TransitionArray::ExpectedTransitionKey(map);
389 follow_expected = !key.is_null() && ParseJsonString(key);
390 }
391 // If the expected transition hits, follow it.
392 if (follow_expected) {
393 target = TransitionArray::ExpectedTransitionTarget(map);
394 } else {
395 // If the expected transition failed, parse an internalized string and
396 // try to find a matching transition.
397 key = ParseJsonInternalizedString();
398 if (key.is_null()) return ReportUnexpectedCharacter();
399
400 target = TransitionArray::FindTransitionToField(map, key);
401 // If a transition was found, follow it and continue.
402 transitioning = !target.is_null();
403 }
404 if (c0_ != ':') return ReportUnexpectedCharacter();
405
406 AdvanceSkipWhitespace();
407 value = ParseJsonValue();
408 if (value.is_null()) return ReportUnexpectedCharacter();
409
363 if (transitioning) { 410 if (transitioning) {
364 // First check whether there is a single expected transition. If so, try 411 PropertyDetails details =
365 // to parse it first. 412 target->instance_descriptors()->GetDetails(descriptor);
366 bool follow_expected = false; 413 Representation expected_representation = details.representation();
367 Handle<Map> target; 414
368 if (seq_one_byte) { 415 if (value->FitsRepresentation(expected_representation)) {
369 key = TransitionArray::ExpectedTransitionKey(map); 416 if (expected_representation.IsHeapObject() &&
370 follow_expected = !key.is_null() && ParseJsonString(key); 417 !target->instance_descriptors()
418 ->GetFieldType(descriptor)
419 ->NowContains(value)) {
420 Handle<HeapType> value_type(
421 value->OptimalType(isolate(), expected_representation));
422 Map::GeneralizeFieldType(target, descriptor,
423 expected_representation, value_type);
424 }
425 DCHECK(target->instance_descriptors()
426 ->GetFieldType(descriptor)
427 ->NowContains(value));
428 properties.Add(value, zone());
429 map = target;
430 descriptor++;
431 continue;
432 } else {
433 transitioning = false;
371 } 434 }
372 // If the expected transition hits, follow it. 435 }
373 if (follow_expected) {
374 target = TransitionArray::ExpectedTransitionTarget(map);
375 } else {
376 // If the expected transition failed, parse an internalized string and
377 // try to find a matching transition.
378 key = ParseJsonInternalizedString();
379 if (key.is_null()) return ReportUnexpectedCharacter();
380 436
381 target = TransitionArray::FindTransitionToField(map, key); 437 DCHECK(!transitioning);
382 // If a transition was found, follow it and continue. 438
383 transitioning = !target.is_null(); 439 // Commit the intermediate state to the object and stop transitioning.
440 CommitStateToJsonObject(json_object, map, &properties);
441
442 Runtime::DefineObjectProperty(json_object, key, value, NONE).Check();
443 } while (transitioning && MatchSkipWhiteSpace(','));
444
445 // If we transitioned until the very end, transition the map now.
446 if (transitioning) {
447 CommitStateToJsonObject(json_object, map, &properties);
448 } else {
449 while (MatchSkipWhiteSpace(',')) {
450 HandleScope local_scope(isolate());
451 if (c0_ != '"') return ReportUnexpectedCharacter();
452
453 int start_position = position_;
454 Advance();
455
456 if (IsDecimalDigit(c0_)) {
457 ParseElementResult element_result = ParseElement(json_object);
458 if (element_result == kNullHandle) return Handle<Object>::null();
459 if (element_result == kElementFound) continue;
384 } 460 }
385 if (c0_ != ':') return ReportUnexpectedCharacter(); 461 // Not an index, fallback to the slow path.
386 462
387 AdvanceSkipWhitespace(); 463 position_ = start_position;
388 value = ParseJsonValue(); 464 #ifdef DEBUG
389 if (value.is_null()) return ReportUnexpectedCharacter(); 465 c0_ = '"';
466 #endif
390 467
391 if (transitioning) { 468 Handle<String> key;
392 PropertyDetails details = 469 Handle<Object> value;
393 target->instance_descriptors()->GetDetails(descriptor);
394 Representation expected_representation = details.representation();
395 470
396 if (value->FitsRepresentation(expected_representation)) {
397 if (expected_representation.IsHeapObject() &&
398 !target->instance_descriptors()
399 ->GetFieldType(descriptor)
400 ->NowContains(value)) {
401 Handle<HeapType> value_type(value->OptimalType(
402 isolate(), expected_representation));
403 Map::GeneralizeFieldType(target, descriptor,
404 expected_representation, value_type);
405 }
406 DCHECK(target->instance_descriptors()->GetFieldType(
407 descriptor)->NowContains(value));
408 properties.Add(value, zone());
409 map = target;
410 descriptor++;
411 continue;
412 } else {
413 transitioning = false;
414 }
415 }
416
417 // Commit the intermediate state to the object and stop transitioning.
418 CommitStateToJsonObject(json_object, map, &properties);
419 } else {
420 key = ParseJsonInternalizedString(); 471 key = ParseJsonInternalizedString();
421 if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter(); 472 if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
422 473
423 AdvanceSkipWhitespace(); 474 AdvanceSkipWhitespace();
424 value = ParseJsonValue(); 475 value = ParseJsonValue();
425 if (value.is_null()) return ReportUnexpectedCharacter(); 476 if (value.is_null()) return ReportUnexpectedCharacter();
477
478 Runtime::DefineObjectProperty(json_object, key, value, NONE).Check();
426 } 479 }
480 }
427 481
428 Runtime::DefineObjectProperty(json_object, key, value, NONE).Check();
429 } while (MatchSkipWhiteSpace(','));
430 if (c0_ != '}') { 482 if (c0_ != '}') {
431 return ReportUnexpectedCharacter(); 483 return ReportUnexpectedCharacter();
432 } 484 }
433
434 // If we transitioned until the very end, transition the map now.
435 if (transitioning) {
436 CommitStateToJsonObject(json_object, map, &properties);
437 }
438 } 485 }
439 AdvanceSkipWhitespace(); 486 AdvanceSkipWhitespace();
440 return scope.CloseAndEscape(json_object); 487 return scope.CloseAndEscape(json_object);
441 } 488 }
442 489
443 490
444 template <bool seq_one_byte> 491 template <bool seq_one_byte>
445 void JsonParser<seq_one_byte>::CommitStateToJsonObject( 492 void JsonParser<seq_one_byte>::CommitStateToJsonObject(
446 Handle<JSObject> json_object, Handle<Map> map, 493 Handle<JSObject> json_object, Handle<Map> map,
447 ZoneList<Handle<Object> >* properties) { 494 ZoneList<Handle<Object> >* properties) {
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 840
794 DCHECK_EQ('"', c0_); 841 DCHECK_EQ('"', c0_);
795 // Advance past the last '"'. 842 // Advance past the last '"'.
796 AdvanceSkipWhitespace(); 843 AdvanceSkipWhitespace();
797 return result; 844 return result;
798 } 845 }
799 846
800 } } // namespace v8::internal 847 } } // namespace v8::internal
801 848
802 #endif // V8_JSON_PARSER_H_ 849 #endif // V8_JSON_PARSER_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698