Skip to content

Commit 50eba5e

Browse files
pthierV8 LUCI CQ
authored andcommitted
[json] Parser: Early return if Expect() fails
Expect()/ExpectNext() used to simply set the cursor to the end of the input if the expectation failed. The issue is that a failed expectation can trigger a GC due to allocation of the Exception object. To avoid surprises, Expect() and ExpectNext() now return a bool value indicating if the expectation failed. Checking of this value is enforced and all current usages are replaced by a Macro that returns early if an exception was thrown. Drive-by: Also force checking the return value of Check(). Fixed: 452296415 Change-Id: I513955f1ea0eb44cd0a59eb2aa57caee8f3082fb Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7048404 Reviewed-by: Igor Sheludko <[email protected]> Commit-Queue: Patrick Thier <[email protected]> Cr-Commit-Position: refs/heads/main@{#103167}
1 parent cac1248 commit 50eba5e

File tree

2 files changed

+50
-29
lines changed

2 files changed

+50
-29
lines changed

src/json/json-parser.cc

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ static const constexpr uint8_t character_json_scan_flags[256] = {
130130
#undef CALL_GET_SCAN_FLAGS
131131
};
132132

133+
#define EXPECT_RETURN_ON_ERROR(token, msg, ret) \
134+
if (V8_UNLIKELY(!Expect(token, msg))) { \
135+
return ret; \
136+
}
137+
#define EXPECT_NEXT_RETURN_ON_ERROR(token, msg, ret) \
138+
if (V8_UNLIKELY(!ExpectNext(token, msg))) { \
139+
return ret; \
140+
}
141+
133142
} // namespace
134143

135144
MaybeHandle<Object> JsonParseInternalizer::Internalize(
@@ -1539,8 +1548,9 @@ bool JsonParser<Char>::FastKeyMatch(const uint8_t* key_chars,
15391548

15401549
template <typename Char>
15411550
bool JsonParser<Char>::ParseJsonPropertyValue(const JsonString& key) {
1542-
ExpectNext(JsonToken::COLON,
1543-
MessageTemplate::kJsonParseExpectedColonAfterPropertyName);
1551+
EXPECT_NEXT_RETURN_ON_ERROR(
1552+
JsonToken::COLON,
1553+
MessageTemplate::kJsonParseExpectedColonAfterPropertyName, false);
15441554
Handle<Object> value;
15451555
if (V8_UNLIKELY(!ParseJsonValueRecursive().ToHandle(&value))) return false;
15461556
property_stack_.emplace_back(key, value);
@@ -1586,7 +1596,7 @@ bool JsonParser<Char>::ParseJsonObjectProperties(
15861596
using FastIterableState = DescriptorArray::FastIterableState;
15871597
if constexpr (fast_iterable_state == FastIterableState::kJsonSlow) {
15881598
do {
1589-
ExpectNext(JsonToken::STRING, first_token_msg);
1599+
EXPECT_NEXT_RETURN_ON_ERROR(JsonToken::STRING, first_token_msg, false);
15901600
first_token_msg =
15911601
MessageTemplate::kJsonParseExpectedDoubleQuotedPropertyName;
15921602
JsonString key = ScanJsonPropertyKey(cont);
@@ -1596,7 +1606,7 @@ bool JsonParser<Char>::ParseJsonObjectProperties(
15961606
DCHECK_GT(descriptors->number_of_descriptors(), 0);
15971607
InternalIndex idx{0};
15981608
do {
1599-
ExpectNext(JsonToken::STRING, first_token_msg);
1609+
EXPECT_NEXT_RETURN_ON_ERROR(JsonToken::STRING, first_token_msg, false);
16001610
first_token_msg =
16011611
MessageTemplate::kJsonParseExpectedDoubleQuotedPropertyName;
16021612
bool key_match;
@@ -1764,7 +1774,8 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonObject(Handle<Map> feedback) {
17641774
return {};
17651775
}
17661776

1767-
Expect(JsonToken::RBRACE, MessageTemplate::kJsonParseExpectedCommaOrRBrace);
1777+
EXPECT_RETURN_ON_ERROR(JsonToken::RBRACE,
1778+
MessageTemplate::kJsonParseExpectedCommaOrRBrace, {});
17681779
Handle<Object> result = BuildJsonObject<false>(cont, feedback);
17691780
property_stack_.resize(cont.index);
17701781
return cont.scope.CloseAndEscape(result);
@@ -1810,8 +1821,9 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonArray() {
18101821
SkipWhitespace();
18111822
continue;
18121823
} else {
1813-
Expect(JsonToken::RBRACK,
1814-
MessageTemplate::kJsonParseExpectedCommaOrRBrack);
1824+
EXPECT_RETURN_ON_ERROR(JsonToken::RBRACK,
1825+
MessageTemplate::kJsonParseExpectedCommaOrRBrack,
1826+
{});
18151827
success = true;
18161828
break;
18171829
}
@@ -1879,7 +1891,8 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonArray() {
18791891
element_stack_.emplace_back(value);
18801892
}
18811893

1882-
Expect(JsonToken::RBRACK, MessageTemplate::kJsonParseExpectedCommaOrRBrack);
1894+
EXPECT_RETURN_ON_ERROR(JsonToken::RBRACK,
1895+
MessageTemplate::kJsonParseExpectedCommaOrRBrack, {});
18831896
Handle<Object> result = BuildJsonArray(start);
18841897
element_stack_.resize(start);
18851898
return handle_scope.CloseAndEscape(result);
@@ -1987,15 +2000,17 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() {
19872000
property_stack_.size());
19882001

19892002
// Parse the property key.
1990-
ExpectNext(JsonToken::STRING,
1991-
MessageTemplate::kJsonParseExpectedPropNameOrRBrace);
2003+
EXPECT_NEXT_RETURN_ON_ERROR(
2004+
JsonToken::STRING,
2005+
MessageTemplate::kJsonParseExpectedPropNameOrRBrace, {});
19922006
property_stack_.emplace_back(ScanJsonPropertyKey(&cont));
19932007
if constexpr (should_track_json_source) {
19942008
property_val_node_stack.emplace_back(Handle<Object>());
19952009
}
19962010

1997-
ExpectNext(JsonToken::COLON,
1998-
MessageTemplate::kJsonParseExpectedColonAfterPropertyName);
2011+
EXPECT_NEXT_RETURN_ON_ERROR(
2012+
JsonToken::COLON,
2013+
MessageTemplate::kJsonParseExpectedColonAfterPropertyName, {});
19992014

20002015
// Continue to start producing the first property value.
20012016
continue;
@@ -2091,17 +2106,18 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() {
20912106

20922107
if (V8_LIKELY(Check(JsonToken::COMMA))) {
20932108
// Parse the property key.
2094-
ExpectNext(
2109+
EXPECT_NEXT_RETURN_ON_ERROR(
20952110
JsonToken::STRING,
2096-
MessageTemplate::kJsonParseExpectedDoubleQuotedPropertyName);
2111+
MessageTemplate::kJsonParseExpectedDoubleQuotedPropertyName,
2112+
{});
20972113

20982114
property_stack_.emplace_back(ScanJsonPropertyKey(&cont));
20992115
if constexpr (should_track_json_source) {
21002116
property_val_node_stack.emplace_back(Handle<Object>());
21012117
}
2102-
ExpectNext(
2118+
EXPECT_NEXT_RETURN_ON_ERROR(
21032119
JsonToken::COLON,
2104-
MessageTemplate::kJsonParseExpectedColonAfterPropertyName);
2120+
MessageTemplate::kJsonParseExpectedColonAfterPropertyName, {});
21052121

21062122
// Break to start producing the subsequent property value.
21072123
break;
@@ -2121,8 +2137,9 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() {
21212137
}
21222138
}
21232139
value = BuildJsonObject<should_track_json_source>(cont, feedback);
2124-
Expect(JsonToken::RBRACE,
2125-
MessageTemplate::kJsonParseExpectedCommaOrRBrace);
2140+
EXPECT_RETURN_ON_ERROR(
2141+
JsonToken::RBRACE,
2142+
MessageTemplate::kJsonParseExpectedCommaOrRBrace, {});
21262143
// Return the object.
21272144
if constexpr (should_track_json_source) {
21282145
size_t start = cont.index;
@@ -2172,8 +2189,9 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() {
21722189
if (V8_LIKELY(Check(JsonToken::COMMA))) break;
21732190

21742191
value = BuildJsonArray(cont.index);
2175-
Expect(JsonToken::RBRACK,
2176-
MessageTemplate::kJsonParseExpectedCommaOrRBrack);
2192+
EXPECT_RETURN_ON_ERROR(
2193+
JsonToken::RBRACK,
2194+
MessageTemplate::kJsonParseExpectedCommaOrRBrack, {});
21772195
// Return the array.
21782196
if constexpr (should_track_json_source) {
21792197
size_t start = cont.index;

src/json/json-parser.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -244,23 +244,26 @@ class JsonParser final {
244244
advance();
245245
}
246246

247-
void Expect(JsonToken token,
248-
std::optional<MessageTemplate> errorMessage = std::nullopt) {
247+
V8_WARN_UNUSED_RESULT bool Expect(
248+
JsonToken token,
249+
std::optional<MessageTemplate> errorMessage = std::nullopt) {
249250
if (V8_LIKELY(peek() == token)) {
250251
advance();
251-
} else {
252-
errorMessage ? ReportUnexpectedToken(peek(), errorMessage.value())
253-
: ReportUnexpectedToken(peek());
252+
return true;
254253
}
254+
errorMessage ? ReportUnexpectedToken(peek(), errorMessage.value())
255+
: ReportUnexpectedToken(peek());
256+
return false;
255257
}
256258

257-
void ExpectNext(JsonToken token,
258-
std::optional<MessageTemplate> errorMessage = std::nullopt) {
259+
V8_WARN_UNUSED_RESULT bool ExpectNext(
260+
JsonToken token,
261+
std::optional<MessageTemplate> errorMessage = std::nullopt) {
259262
SkipWhitespace();
260-
errorMessage ? Expect(token, errorMessage.value()) : Expect(token);
263+
return errorMessage ? Expect(token, errorMessage.value()) : Expect(token);
261264
}
262265

263-
bool Check(JsonToken token) {
266+
V8_WARN_UNUSED_RESULT bool Check(JsonToken token) {
264267
SkipWhitespace();
265268
if (next_ != token) return false;
266269
advance();

0 commit comments

Comments
 (0)