reader/wgsl: Prevent stack overflow in unary_expression()
Fixed: chromium:1209237 Change-Id: I14b4777aaee3ee7a34baf8a218db28f54b81af84 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/55253 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: James Price <jrprice@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
055901b3cd
commit
e7257eb2fb
|
@ -52,10 +52,10 @@ using Expect = ParserImpl::Expect<T>;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using Maybe = ParserImpl::Maybe<T>;
|
using Maybe = ParserImpl::Maybe<T>;
|
||||||
|
|
||||||
/// Controls the maximum number of times we'll call into the sync() function
|
/// Controls the maximum number of times we'll call into the sync() and
|
||||||
/// from itself. This is to guard against stack overflow when there is an
|
/// unary_expression() functions from themselves. This is to guard against stack
|
||||||
/// excessive number of blocks.
|
/// overflow when there is an excessive number of blocks.
|
||||||
constexpr uint32_t kMaxSyncDepth = 128;
|
constexpr uint32_t kMaxParseDepth = 128;
|
||||||
|
|
||||||
/// The maximum number of tokens to look ahead to try and sync the
|
/// The maximum number of tokens to look ahead to try and sync the
|
||||||
/// parser on error.
|
/// parser on error.
|
||||||
|
@ -2327,7 +2327,18 @@ Maybe<ast::Expression*> ParserImpl::unary_expression() {
|
||||||
return singular_expression();
|
return singular_expression();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parse_depth_ >= kMaxParseDepth) {
|
||||||
|
// We've hit a maximum parser recursive depth.
|
||||||
|
// We can't call into unary_expression() as we might stack overflow.
|
||||||
|
// Instead, report an error
|
||||||
|
add_error(peek(), "maximum parser recursive depth reached");
|
||||||
|
return Failure::kErrored;
|
||||||
|
}
|
||||||
|
|
||||||
|
++parse_depth_;
|
||||||
auto expr = unary_expression();
|
auto expr = unary_expression();
|
||||||
|
--parse_depth_;
|
||||||
|
|
||||||
if (expr.errored) {
|
if (expr.errored) {
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
@ -3268,7 +3279,7 @@ T ParserImpl::expect_lt_gt_block(const std::string& use, F&& body) {
|
||||||
|
|
||||||
template <typename F, typename T>
|
template <typename F, typename T>
|
||||||
T ParserImpl::sync(Token::Type tok, F&& body) {
|
T ParserImpl::sync(Token::Type tok, F&& body) {
|
||||||
if (sync_depth_ >= kMaxSyncDepth) {
|
if (parse_depth_ >= kMaxParseDepth) {
|
||||||
// We've hit a maximum parser recursive depth.
|
// We've hit a maximum parser recursive depth.
|
||||||
// We can't call into body() as we might stack overflow.
|
// We can't call into body() as we might stack overflow.
|
||||||
// Instead, report an error...
|
// Instead, report an error...
|
||||||
|
@ -3282,9 +3293,9 @@ T ParserImpl::sync(Token::Type tok, F&& body) {
|
||||||
|
|
||||||
sync_tokens_.push_back(tok);
|
sync_tokens_.push_back(tok);
|
||||||
|
|
||||||
++sync_depth_;
|
++parse_depth_;
|
||||||
auto result = body();
|
auto result = body();
|
||||||
--sync_depth_;
|
--parse_depth_;
|
||||||
|
|
||||||
if (sync_tokens_.back() != tok) {
|
if (sync_tokens_.back() != tok) {
|
||||||
TINT_ICE(builder_.Diagnostics()) << "sync_tokens is out of sync";
|
TINT_ICE(builder_.Diagnostics()) << "sync_tokens is out of sync";
|
||||||
|
|
|
@ -871,7 +871,7 @@ class ParserImpl {
|
||||||
std::deque<Token> token_queue_;
|
std::deque<Token> token_queue_;
|
||||||
Token last_token_;
|
Token last_token_;
|
||||||
bool synchronized_ = true;
|
bool synchronized_ = true;
|
||||||
uint32_t sync_depth_ = 0;
|
uint32_t parse_depth_ = 0;
|
||||||
std::vector<Token::Type> sync_tokens_;
|
std::vector<Token::Type> sync_tokens_;
|
||||||
int silence_errors_ = 0;
|
int silence_errors_ = 0;
|
||||||
std::unordered_map<std::string, const ast::TypeDecl*> registered_types_;
|
std::unordered_map<std::string, const ast::TypeDecl*> registered_types_;
|
||||||
|
|
|
@ -154,6 +154,20 @@ TEST_F(ParserImplTest, ConstExpr_Recursion) {
|
||||||
EXPECT_EQ(p->error(), "1:517: maximum parser recursive depth reached");
|
EXPECT_EQ(p->error(), "1:517: maximum parser recursive depth reached");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplTest, UnaryOp_Recursion) {
|
||||||
|
std::stringstream out;
|
||||||
|
for (size_t i = 0; i < 200; i++) {
|
||||||
|
out << "!";
|
||||||
|
}
|
||||||
|
out << "1.0";
|
||||||
|
auto p = parser(out.str());
|
||||||
|
auto e = p->unary_expression();
|
||||||
|
ASSERT_TRUE(p->has_error());
|
||||||
|
ASSERT_TRUE(e.errored);
|
||||||
|
ASSERT_EQ(e.value, nullptr);
|
||||||
|
EXPECT_EQ(p->error(), "1:130: maximum parser recursive depth reached");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace wgsl
|
} // namespace wgsl
|
||||||
} // namespace reader
|
} // namespace reader
|
||||||
|
|
Loading…
Reference in New Issue