tint: validate max number of members in a struct
Bug: tint:1209 Change-Id: I248c1864d3b38d41eda56bc41d7f19fb5fdd1955 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/121220 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
parent
8cd5c611fc
commit
8ef7311413
|
@ -45,6 +45,8 @@ std::string DisableValidationAttribute::InternalName() const {
|
||||||
return "disable_validation__ignore_invalid_pointer_argument";
|
return "disable_validation__ignore_invalid_pointer_argument";
|
||||||
case DisabledValidation::kIgnorePointerAliasing:
|
case DisabledValidation::kIgnorePointerAliasing:
|
||||||
return "disable_validation__ignore_pointer_aliasing";
|
return "disable_validation__ignore_pointer_aliasing";
|
||||||
|
case DisabledValidation::kIgnoreStructMemberLimit:
|
||||||
|
return "disable_validation__ignore_struct_member";
|
||||||
}
|
}
|
||||||
return "<invalid>";
|
return "<invalid>";
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,8 @@ enum class DisabledValidation {
|
||||||
/// When applied to a function declaration, the validator will not complain if multiple
|
/// When applied to a function declaration, the validator will not complain if multiple
|
||||||
/// pointer arguments alias when that function is called.
|
/// pointer arguments alias when that function is called.
|
||||||
kIgnorePointerAliasing,
|
kIgnorePointerAliasing,
|
||||||
|
/// When applied to a struct, validation of max number of members is skipped.
|
||||||
|
kIgnoreStructMemberLimit,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An internal attribute used to tell the validator to ignore specific
|
/// An internal attribute used to tell the validator to ignore specific
|
||||||
|
|
|
@ -3573,6 +3573,20 @@ type::Type* Resolver::Alias(const ast::Alias* alias) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
||||||
|
if (validator_.IsValidationEnabled(str->attributes,
|
||||||
|
ast::DisabledValidation::kIgnoreStructMemberLimit)) {
|
||||||
|
// Maximum number of members in a structure type
|
||||||
|
// https://gpuweb.github.io/gpuweb/wgsl/#limits
|
||||||
|
const size_t kMaxNumStructMembers = 16383;
|
||||||
|
if (str->members.Length() > kMaxNumStructMembers) {
|
||||||
|
AddError("struct '" + builder_->Symbols().NameFor(str->name->symbol) + "' has " +
|
||||||
|
std::to_string(str->members.Length()) + " members, maximum is " +
|
||||||
|
std::to_string(kMaxNumStructMembers),
|
||||||
|
str->source);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!validator_.NoDuplicateAttributes(str->attributes)) {
|
if (!validator_.NoDuplicateAttributes(str->attributes)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2394,5 +2394,45 @@ TEST_F(ResolverTest, ScopeDepth_IfElseChain) {
|
||||||
|
|
||||||
#endif // !defined(NDEBUG)
|
#endif // !defined(NDEBUG)
|
||||||
|
|
||||||
|
const size_t kMaxNumStructMembers = 16383;
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNumStructMembers_Valid) {
|
||||||
|
utils::Vector<const ast::StructMember*, 0> members;
|
||||||
|
members.Reserve(kMaxNumStructMembers);
|
||||||
|
for (size_t i = 0; i < kMaxNumStructMembers; ++i) {
|
||||||
|
members.Push(Member("m" + std::to_string(i), ty.i32()));
|
||||||
|
}
|
||||||
|
Structure("S", std::move(members));
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNumStructMembers_Invalid) {
|
||||||
|
utils::Vector<const ast::StructMember*, 0> members;
|
||||||
|
members.Reserve(kMaxNumStructMembers + 1);
|
||||||
|
for (size_t i = 0; i < kMaxNumStructMembers + 1; ++i) {
|
||||||
|
members.Push(Member("m" + std::to_string(i), ty.i32()));
|
||||||
|
}
|
||||||
|
Structure(Source{{12, 34}}, "S", std::move(members));
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: struct 'S' has 16384 members, maximum is 16383");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNumStructMembers_WithIgnoreStructMemberLimit_Valid) {
|
||||||
|
utils::Vector<const ast::StructMember*, 0> members;
|
||||||
|
members.Reserve(kMaxNumStructMembers);
|
||||||
|
for (size_t i = 0; i < kMaxNumStructMembers; ++i) {
|
||||||
|
members.Push(Member("m" + std::to_string(i), ty.i32()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add 10 more members, but we set the limit to be ignored on the struct
|
||||||
|
for (size_t i = 0; i < 10; ++i) {
|
||||||
|
members.Push(Member("ignored" + std::to_string(i), ty.i32()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Structure("S", std::move(members),
|
||||||
|
utils::Vector{Disable(ast::DisabledValidation::kIgnoreStructMemberLimit)});
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "src/tint/ast/disable_validation_attribute.h"
|
||||||
#include "src/tint/ast/parameter.h"
|
#include "src/tint/ast/parameter.h"
|
||||||
#include "src/tint/program_builder.h"
|
#include "src/tint/program_builder.h"
|
||||||
#include "src/tint/sem/call.h"
|
#include "src/tint/sem/call.h"
|
||||||
|
@ -36,7 +37,10 @@ void CreatePadding(utils::Vector<const ast::StructMember*, 8>* new_members,
|
||||||
utils::Hashset<const ast::StructMember*, 8>* padding_members,
|
utils::Hashset<const ast::StructMember*, 8>* padding_members,
|
||||||
ProgramBuilder* b,
|
ProgramBuilder* b,
|
||||||
uint32_t bytes) {
|
uint32_t bytes) {
|
||||||
for (uint32_t i = 0; i < bytes / 4u; ++i) {
|
const size_t count = bytes / 4u;
|
||||||
|
padding_members->Reserve(count);
|
||||||
|
new_members->Reserve(count);
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
auto name = b->Symbols().New("pad");
|
auto name = b->Symbols().New("pad");
|
||||||
auto* member = b->Member(name, b->ty.u32());
|
auto* member = b->Member(name, b->ty.u32());
|
||||||
padding_members->Add(member);
|
padding_members->Add(member);
|
||||||
|
@ -99,8 +103,15 @@ Transform::ApplyResult PadStructs::Apply(const Program* src, const DataMap&, Dat
|
||||||
if (offset < struct_size && !has_runtime_sized_array) {
|
if (offset < struct_size && !has_runtime_sized_array) {
|
||||||
CreatePadding(&new_members, &padding_members, ctx.dst, struct_size - offset);
|
CreatePadding(&new_members, &padding_members, ctx.dst, struct_size - offset);
|
||||||
}
|
}
|
||||||
auto* new_struct =
|
|
||||||
b.create<ast::Struct>(ctx.Clone(ast_str->name), std::move(new_members), utils::Empty);
|
utils::Vector<const ast::Attribute*, 1> struct_attribs;
|
||||||
|
if (!padding_members.IsEmpty()) {
|
||||||
|
struct_attribs =
|
||||||
|
utils::Vector{b.Disable(ast::DisabledValidation::kIgnoreStructMemberLimit)};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* new_struct = b.create<ast::Struct>(ctx.Clone(ast_str->name), std::move(new_members),
|
||||||
|
std::move(struct_attribs));
|
||||||
replaced_structs[ast_str] = new_struct;
|
replaced_structs[ast_str] = new_struct;
|
||||||
return new_struct;
|
return new_struct;
|
||||||
});
|
});
|
||||||
|
|
|
@ -47,6 +47,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
x : i32,
|
x : i32,
|
||||||
pad : u32,
|
pad : u32,
|
||||||
|
@ -81,6 +82,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
x : i32,
|
x : i32,
|
||||||
pad : u32,
|
pad : u32,
|
||||||
|
@ -118,6 +120,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
x : i32,
|
x : i32,
|
||||||
pad : u32,
|
pad : u32,
|
||||||
|
@ -158,6 +161,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
x : i32,
|
x : i32,
|
||||||
pad : u32,
|
pad : u32,
|
||||||
|
@ -198,6 +202,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
x : i32,
|
x : i32,
|
||||||
pad : u32,
|
pad : u32,
|
||||||
|
@ -273,6 +278,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
a : i32,
|
a : i32,
|
||||||
pad : u32,
|
pad : u32,
|
||||||
|
@ -320,6 +326,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
a : i32,
|
a : i32,
|
||||||
pad : u32,
|
pad : u32,
|
||||||
|
@ -367,6 +374,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
a : i32,
|
a : i32,
|
||||||
pad : u32,
|
pad : u32,
|
||||||
|
@ -501,6 +509,7 @@ struct T {
|
||||||
b : i32,
|
b : i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
a : vec4<f32>,
|
a : vec4<f32>,
|
||||||
b : array<T, 1u>,
|
b : array<T, 1u>,
|
||||||
|
@ -537,6 +546,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
a : f32,
|
a : f32,
|
||||||
pad : u32,
|
pad : u32,
|
||||||
|
@ -573,6 +583,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
auto* expect = R"(
|
auto* expect = R"(
|
||||||
|
@internal(disable_validation__ignore_struct_member)
|
||||||
struct S {
|
struct S {
|
||||||
a : f32,
|
a : f32,
|
||||||
pad : u32,
|
pad : u32,
|
||||||
|
|
Loading…
Reference in New Issue