From 5509cc2c07441a2d004c5674a77a3bf03b10a287 Mon Sep 17 00:00:00 2001 From: "ishell@chromium.org" Date: Thu, 23 Oct 2014 14:41:39 +0000 Subject: [PATCH] Fixed mutable heap numbers leak in JSON parser. BUG=chromium:423687 LOG=N R=verwaest@chromium.org Review URL: https://codereview.chromium.org/669403002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24849 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/json-parser.h | 56 +++++++++++++++++++++------- test/mjsunit/regress/regress-crbug-423687.js | 10 +++++ 2 files changed, 52 insertions(+), 14 deletions(-) create mode 100644 test/mjsunit/regress/regress-crbug-423687.js diff --git a/src/json-parser.h b/src/json-parser.h index d3148c9..2993249 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 json_object, Handle map, + ZoneList >* properties); + Handle source_; int source_length_; Handle seq_source_; @@ -410,13 +413,7 @@ Handle JsonParser::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 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 JsonParser::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 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 +void JsonParser::CommitStateToJsonObject( + Handle json_object, Handle map, + ZoneList >* 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 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 Handle JsonParser::ParseJsonArray() { diff --git a/test/mjsunit/regress/regress-crbug-423687.js b/test/mjsunit/regress/regress-crbug-423687.js new file mode 100644 index 0000000..6000352 --- /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++; -- 2.7.4