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

Unified 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, 9 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 side-by-side diff with in-line comments
Download patch
Index: src/json-parser.h
diff --git a/src/json-parser.h b/src/json-parser.h
index 1a9a36f283513bab2f3b72d2d6e5a78c6d0d2de8..39d9c38b44c7e8a7775b21fd1da581409c912ed0 100644
--- a/src/json-parser.h
+++ b/src/json-parser.h
@@ -16,6 +16,9 @@
namespace v8 {
namespace internal {
+enum ParseElementResult { kElementFound, kElementNotFound, kNullHandle };
+
+
// A simple json parser.
template <bool seq_one_byte>
class JsonParser BASE_EMBEDDED {
@@ -155,6 +158,10 @@ class JsonParser BASE_EMBEDDED {
// JavaScript array.
Handle<Object> ParseJsonObject();
+ // Helper for ParseJsonObject. Parses the form "123": obj, which is recorded
+ // as an element, not a property.
+ ParseElementResult ParseElement(Handle<JSObject> json_object);
+
// Parses a JSON array literal (grammar production JSONArray). An array
// literal is a square-bracketed and comma separated sequence (possibly empty)
// of JSON values.
@@ -299,6 +306,41 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonValue() {
}
+template <bool seq_one_byte>
+ParseElementResult JsonParser<seq_one_byte>::ParseElement(
+ Handle<JSObject> json_object) {
+ uint32_t index = 0;
+ // Maybe an array index, try to parse it.
+ if (c0_ == '0') {
+ // With a leading zero, the string has to be "0" only to be an index.
+ Advance();
+ } else {
+ do {
+ int d = c0_ - '0';
+ if (index > 429496729U - ((d > 5) ? 1 : 0)) break;
+ index = (index * 10) + d;
+ Advance();
+ } while (IsDecimalDigit(c0_));
+ }
+
+ if (c0_ == '"') {
+ // Successfully parsed index, parse and store element.
+ AdvanceSkipWhitespace();
+
+ if (c0_ == ':') {
+ AdvanceSkipWhitespace();
+ Handle<Object> value = ParseJsonValue();
+ if (!value.is_null()) {
+ JSObject::SetOwnElement(json_object, index, value, SLOPPY).Assert();
+ return kElementFound;
+ } else {
+ return kNullHandle;
+ }
+ }
+ }
+ return kElementNotFound;
+}
+
// Parse a JSON object. Position must be right at '{'.
template <bool seq_one_byte>
Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
@@ -320,35 +362,12 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
int start_position = position_;
Advance();
- uint32_t index = 0;
if (IsDecimalDigit(c0_)) {
- // Maybe an array index, try to parse it.
- if (c0_ == '0') {
- // With a leading zero, the string has to be "0" only to be an index.
- Advance();
- } else {
- do {
- int d = c0_ - '0';
- if (index > 429496729U - ((d > 5) ? 1 : 0)) break;
- index = (index * 10) + d;
- Advance();
- } while (IsDecimalDigit(c0_));
- }
-
- if (c0_ == '"') {
- // Successfully parsed index, parse and store element.
- AdvanceSkipWhitespace();
-
- if (c0_ != ':') return ReportUnexpectedCharacter();
- AdvanceSkipWhitespace();
- Handle<Object> value = ParseJsonValue();
- if (value.is_null()) return ReportUnexpectedCharacter();
-
- JSObject::SetOwnElement(json_object, index, value, SLOPPY).Assert();
- continue;
- }
- // Not an index, fallback to the slow path.
+ ParseElementResult element_result = ParseElement(json_object);
+ if (element_result == kNullHandle) return Handle<Object>::null();
+ if (element_result == kElementFound) continue;
}
+ // Not an index, fallback to the slow path.
position_ = start_position;
#ifdef DEBUG
@@ -360,81 +379,109 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
// Try to follow existing transitions as long as possible. Once we stop
// transitioning, no transition can be found anymore.
+ DCHECK(transitioning);
+ // First check whether there is a single expected transition. If so, try
+ // to parse it first.
+ bool follow_expected = false;
+ Handle<Map> target;
+ if (seq_one_byte) {
+ key = TransitionArray::ExpectedTransitionKey(map);
+ follow_expected = !key.is_null() && ParseJsonString(key);
+ }
+ // If the expected transition hits, follow it.
+ if (follow_expected) {
+ target = TransitionArray::ExpectedTransitionTarget(map);
+ } else {
+ // If the expected transition failed, parse an internalized string and
+ // try to find a matching transition.
+ key = ParseJsonInternalizedString();
+ if (key.is_null()) return ReportUnexpectedCharacter();
+
+ target = TransitionArray::FindTransitionToField(map, key);
+ // If a transition was found, follow it and continue.
+ transitioning = !target.is_null();
+ }
+ if (c0_ != ':') return ReportUnexpectedCharacter();
+
+ AdvanceSkipWhitespace();
+ value = ParseJsonValue();
+ if (value.is_null()) return ReportUnexpectedCharacter();
+
if (transitioning) {
- // First check whether there is a single expected transition. If so, try
- // to parse it first.
- bool follow_expected = false;
- Handle<Map> target;
- if (seq_one_byte) {
- key = TransitionArray::ExpectedTransitionKey(map);
- follow_expected = !key.is_null() && ParseJsonString(key);
- }
- // If the expected transition hits, follow it.
- if (follow_expected) {
- target = TransitionArray::ExpectedTransitionTarget(map);
+ PropertyDetails details =
+ target->instance_descriptors()->GetDetails(descriptor);
+ Representation expected_representation = details.representation();
+
+ if (value->FitsRepresentation(expected_representation)) {
+ if (expected_representation.IsHeapObject() &&
+ !target->instance_descriptors()
+ ->GetFieldType(descriptor)
+ ->NowContains(value)) {
+ Handle<HeapType> value_type(
+ value->OptimalType(isolate(), expected_representation));
+ Map::GeneralizeFieldType(target, descriptor,
+ expected_representation, value_type);
+ }
+ DCHECK(target->instance_descriptors()
+ ->GetFieldType(descriptor)
+ ->NowContains(value));
+ properties.Add(value, zone());
+ map = target;
+ descriptor++;
+ continue;
} else {
- // If the expected transition failed, parse an internalized string and
- // try to find a matching transition.
- key = ParseJsonInternalizedString();
- if (key.is_null()) return ReportUnexpectedCharacter();
-
- target = TransitionArray::FindTransitionToField(map, key);
- // If a transition was found, follow it and continue.
- transitioning = !target.is_null();
+ transitioning = false;
}
- if (c0_ != ':') return ReportUnexpectedCharacter();
+ }
- AdvanceSkipWhitespace();
- value = ParseJsonValue();
- if (value.is_null()) return ReportUnexpectedCharacter();
+ DCHECK(!transitioning);
- if (transitioning) {
- PropertyDetails details =
- target->instance_descriptors()->GetDetails(descriptor);
- Representation expected_representation = details.representation();
+ // Commit the intermediate state to the object and stop transitioning.
+ CommitStateToJsonObject(json_object, map, &properties);
- if (value->FitsRepresentation(expected_representation)) {
- if (expected_representation.IsHeapObject() &&
- !target->instance_descriptors()
- ->GetFieldType(descriptor)
- ->NowContains(value)) {
- Handle<HeapType> value_type(value->OptimalType(
- isolate(), expected_representation));
- Map::GeneralizeFieldType(target, descriptor,
- expected_representation, value_type);
- }
- DCHECK(target->instance_descriptors()->GetFieldType(
- descriptor)->NowContains(value));
- properties.Add(value, zone());
- map = target;
- descriptor++;
- continue;
- } else {
- transitioning = false;
- }
+ Runtime::DefineObjectProperty(json_object, key, value, NONE).Check();
+ } while (transitioning && MatchSkipWhiteSpace(','));
+
+ // If we transitioned until the very end, transition the map now.
+ if (transitioning) {
+ CommitStateToJsonObject(json_object, map, &properties);
+ } else {
+ while (MatchSkipWhiteSpace(',')) {
+ HandleScope local_scope(isolate());
+ if (c0_ != '"') return ReportUnexpectedCharacter();
+
+ int start_position = position_;
+ Advance();
+
+ if (IsDecimalDigit(c0_)) {
+ ParseElementResult element_result = ParseElement(json_object);
+ if (element_result == kNullHandle) return Handle<Object>::null();
+ if (element_result == kElementFound) continue;
}
+ // Not an index, fallback to the slow path.
+
+ position_ = start_position;
+#ifdef DEBUG
+ c0_ = '"';
+#endif
+
+ Handle<String> key;
+ Handle<Object> value;
- // Commit the intermediate state to the object and stop transitioning.
- CommitStateToJsonObject(json_object, map, &properties);
- } else {
key = ParseJsonInternalizedString();
if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter();
AdvanceSkipWhitespace();
value = ParseJsonValue();
if (value.is_null()) return ReportUnexpectedCharacter();
+
+ Runtime::DefineObjectProperty(json_object, key, value, NONE).Check();
}
+ }
- Runtime::DefineObjectProperty(json_object, key, value, NONE).Check();
- } while (MatchSkipWhiteSpace(','));
if (c0_ != '}') {
return ReportUnexpectedCharacter();
}
-
- // If we transitioned until the very end, transition the map now.
- if (transitioning) {
- CommitStateToJsonObject(json_object, map, &properties);
- }
}
AdvanceSkipWhitespace();
return scope.CloseAndEscape(json_object);

Powered by Google App Engine
This is Rietveld 408576698