aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorishell@chromium.org <ishell@chromium.org>2014-11-04 15:10:33 +0000
committerishell@chromium.org <ishell@chromium.org>2014-11-04 15:11:15 +0000
commit144d97d24909783cb4f72356da27b1b815446053 (patch)
tree2d7a5ec1fd9d73105806deaba34d6f2956d0d253
parent43490db4c9020e4d16f93816160b051c8cdf1ce9 (diff)
downloadv8-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.h56
-rw-r--r--src/version.cc2
-rw-r--r--test/mjsunit/regress/regress-crbug-423687.js10
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++;