diff options
author | ishell@chromium.org <ishell@chromium.org> | 2014-11-04 15:10:33 +0000 |
---|---|---|
committer | ishell@chromium.org <ishell@chromium.org> | 2014-11-04 15:11:15 +0000 |
commit | 144d97d24909783cb4f72356da27b1b815446053 (patch) | |
tree | 2d7a5ec1fd9d73105806deaba34d6f2956d0d253 | |
parent | 43490db4c9020e4d16f93816160b051c8cdf1ce9 (diff) | |
download | v8-144d97d24909783cb4f72356da27b1b815446053.tar.gz |
Version 3.29.88.15 (merged r24849)
Fixed mutable heap numbers leak in JSON parser.
BUG=chromium:423687
LOG=N
R=verwaest@chromium.org
Review URL: https://codereview.chromium.org/705583002
Cr-Commit-Position: refs/branch-heads/3.29@{#25112}
git-svn-id: https://v8.googlecode.com/svn/branches/3.29@25112 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
-rw-r--r-- | src/json-parser.h | 56 | ||||
-rw-r--r-- | src/version.cc | 2 | ||||
-rw-r--r-- | test/mjsunit/regress/regress-crbug-423687.js | 10 |
3 files changed, 53 insertions, 15 deletions
diff --git a/src/json-parser.h b/src/json-parser.h index d3148c9e2..29932492d 100644 --- a/src/json-parser.h +++ b/src/json-parser.h @@ -182,6 +182,9 @@ class JsonParser BASE_EMBEDDED { private: Zone* zone() { return &zone_; } + void CommitStateToJsonObject(Handle<JSObject> json_object, Handle<Map> map, + ZoneList<Handle<Object> >* properties); + Handle<String> source_; int source_length_; Handle<SeqOneByteString> seq_source_; @@ -410,13 +413,7 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { } // Commit the intermediate state to the object and stop transitioning. - JSObject::AllocateStorageForMap(json_object, map); - int length = properties.length(); - for (int i = 0; i < length; i++) { - Handle<Object> value = properties[i]; - FieldIndex index = FieldIndex::ForPropertyIndex(*map, i); - json_object->FastPropertyAtPut(index, *value); - } + CommitStateToJsonObject(json_object, map, &properties); } else { key = ParseJsonInternalizedString(); if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter(); @@ -434,19 +431,50 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { // If we transitioned until the very end, transition the map now. if (transitioning) { - JSObject::AllocateStorageForMap(json_object, map); - int length = properties.length(); - for (int i = 0; i < length; i++) { - Handle<Object> value = properties[i]; - FieldIndex index = FieldIndex::ForPropertyIndex(*map, i); - json_object->FastPropertyAtPut(index, *value); - } + CommitStateToJsonObject(json_object, map, &properties); } } AdvanceSkipWhitespace(); return scope.CloseAndEscape(json_object); } + +template <bool seq_one_byte> +void JsonParser<seq_one_byte>::CommitStateToJsonObject( + Handle<JSObject> json_object, Handle<Map> map, + ZoneList<Handle<Object> >* properties) { + JSObject::AllocateStorageForMap(json_object, map); + DCHECK(!json_object->map()->is_dictionary_map()); + + DisallowHeapAllocation no_gc; + Factory* factory = isolate()->factory(); + // If the |json_object|'s map is exactly the same as |map| then the + // |properties| values correspond to the |map| and nothing more has to be + // done. But if the |json_object|'s map is different then we have to + // iterate descriptors to ensure that properties still correspond to the + // map. + bool slow_case = json_object->map() != *map; + DescriptorArray* descriptors = NULL; + + int length = properties->length(); + if (slow_case) { + descriptors = json_object->map()->instance_descriptors(); + DCHECK(json_object->map()->NumberOfOwnDescriptors() == length); + } + for (int i = 0; i < length; i++) { + Handle<Object> value = (*properties)[i]; + if (slow_case && value->IsMutableHeapNumber() && + !descriptors->GetDetails(i).representation().IsDouble()) { + // Turn mutable heap numbers into immutable if the field representation + // is not double. + HeapNumber::cast(*value)->set_map(*factory->heap_number_map()); + } + FieldIndex index = FieldIndex::ForPropertyIndex(*map, i); + json_object->FastPropertyAtPut(index, *value); + } +} + + // Parse a JSON array. Position must be right at '['. template <bool seq_one_byte> Handle<Object> JsonParser<seq_one_byte>::ParseJsonArray() { diff --git a/src/version.cc b/src/version.cc index 54897660d..75846224d 100644 --- a/src/version.cc +++ b/src/version.cc @@ -35,7 +35,7 @@ #define MAJOR_VERSION 3 #define MINOR_VERSION 29 #define BUILD_NUMBER 88 -#define PATCH_LEVEL 14 +#define PATCH_LEVEL 15 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0 diff --git a/test/mjsunit/regress/regress-crbug-423687.js b/test/mjsunit/regress/regress-crbug-423687.js new file mode 100644 index 000000000..60003527e --- /dev/null +++ b/test/mjsunit/regress/regress-crbug-423687.js @@ -0,0 +1,10 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +var json = '{"a":{"c":2.1,"d":0},"b":{"c":7,"1024":8}}'; +var data = JSON.parse(json); + +data.b.c++; |