tint/resolver: Limit scope depth / if-chains.

DXC will bail if these get too deeply nested (~256).
This is also a risk for stack-overflows, so apply a limit agreed by the
WGSL working group.

Fixed: tint:1518
Change-Id: Idacdba85b36b27a0a89a3a7958fd4c6cce7dc84d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/105964
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
Ben Clayton
2022-10-25 16:53:06 +00:00
committed by Dawn LUCI CQ
parent 3a6b5362d5
commit bd5bd247f0
10 changed files with 2723 additions and 1 deletions

View File

@@ -93,6 +93,7 @@ namespace tint::resolver {
namespace {
constexpr int64_t kMaxArrayElementCount = 65536;
constexpr uint32_t kMaxStatementDepth = 127;
} // namespace
@@ -3400,6 +3401,14 @@ SEM* Resolver::StatementScope(const ast::Statement* ast, SEM* sem, F&& callback)
TINT_SCOPED_ASSIGNMENT(current_statement_, sem);
TINT_SCOPED_ASSIGNMENT(current_compound_statement_,
as_compound ? as_compound : current_compound_statement_);
TINT_SCOPED_ASSIGNMENT(current_scoping_depth_, current_scoping_depth_ + 1);
if (current_scoping_depth_ > kMaxStatementDepth) {
AddError("statement nesting depth / chaining length exceeds limit of " +
std::to_string(kMaxStatementDepth),
ast->source);
return nullptr;
}
if (!callback()) {
return nullptr;

View File

@@ -377,7 +377,8 @@ class Resolver {
/// * Assigns `sem` to #current_compound_statement_ if `sem` derives from
/// sem::CompoundStatement.
/// * Then calls `callback`.
/// * Before returning #current_statement_ and #current_compound_statement_ are restored to their original values.
/// * Before returning #current_statement_ and #current_compound_statement_ are restored to
/// their original values.
/// @returns `sem` if `callback` returns true, otherwise `nullptr`.
template <typename SEM, typename F>
SEM* StatementScope(const ast::Statement* ast, SEM* sem, F&& callback);
@@ -439,6 +440,7 @@ class Resolver {
sem::Function* current_function_ = nullptr;
sem::Statement* current_statement_ = nullptr;
sem::CompoundStatement* current_compound_statement_ = nullptr;
uint32_t current_scoping_depth_ = 0;
};
} // namespace tint::resolver

View File

@@ -2331,5 +2331,47 @@ TEST_F(ResolverTest, Literal_F16WithExtension) {
EXPECT_TRUE(r()->Resolve());
}
// Windows debug builds have significantly smaller stack than other builds, and these tests will stack
// overflow.
#if !defined(NDEBUG)
TEST_F(ResolverTest, ScopeDepth_NestedBlocks) {
const ast::Statement* stmt = Return();
for (size_t i = 0; i < 150; i++) {
stmt = Block(Source{{i, 1}}, stmt);
}
WrapInFunction(stmt);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"23:1 error: statement nesting depth / chaining length exceeds limit of 127");
}
TEST_F(ResolverTest, ScopeDepth_NestedIf) {
const ast::Statement* stmt = Return();
for (size_t i = 0; i < 150; i++) {
stmt = If(Source{{i, 1}}, false, Block(Source{{i, 2}}, stmt));
}
WrapInFunction(stmt);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"86:1 error: statement nesting depth / chaining length exceeds limit of 127");
}
TEST_F(ResolverTest, ScopeDepth_IfElseChain) {
const ast::Statement* stmt = nullptr;
for (size_t i = 0; i < 150; i++) {
stmt = If(Source{{i, 1}}, false, Block(Source{{i, 2}}), Else(stmt));
}
WrapInFunction(stmt);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"24:2 error: statement nesting depth / chaining length exceeds limit of 127");
}
#endif // !defined(NDEBUG)
} // namespace
} // namespace tint::resolver