tint/writer: Do not attempt to use invalid programs

Attempting to emit shader code from an invalid program is unsafe.

The WGSL writer is used for dumping information which is valuable for debugging bad programs, so this has not been changed.

Bug: chromium:1327461
Change-Id: I4497fcb19d126ef6c872e2bcda8e9b79044aeb68
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/91163
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/writer/glsl/generator.cc b/src/tint/writer/glsl/generator.cc
index 4b6da68..4b1e516 100644
--- a/src/tint/writer/glsl/generator.cc
+++ b/src/tint/writer/glsl/generator.cc
@@ -30,6 +30,10 @@
 
 Result Generate(const Program* program, const Options& options, const std::string& entry_point) {
     Result result;
+    if (!program->IsValid()) {
+        result.error = "input program is not valid";
+        return result;
+    }
 
     // Sanitize the program.
     auto sanitized_result = Sanitize(program, options, entry_point);
diff --git a/src/tint/writer/glsl/generator_impl_test.cc b/src/tint/writer/glsl/generator_impl_test.cc
index ad11413..af2e205 100644
--- a/src/tint/writer/glsl/generator_impl_test.cc
+++ b/src/tint/writer/glsl/generator_impl_test.cc
@@ -19,6 +19,15 @@
 
 using GlslGeneratorImplTest = TestHelper;
 
+TEST_F(GlslGeneratorImplTest, InvalidProgram) {
+    Diagnostics().add_error(diag::System::Writer, "make the program invalid");
+    ASSERT_FALSE(IsValid());
+    auto program = std::make_unique<Program>(std::move(*this));
+    ASSERT_FALSE(program->IsValid());
+    auto result = Generate(program.get(), Options{}, "");
+    EXPECT_EQ(result.error, "input program is not valid");
+}
+
 TEST_F(GlslGeneratorImplTest, Generate) {
     Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
 
diff --git a/src/tint/writer/hlsl/generator.cc b/src/tint/writer/hlsl/generator.cc
index ff3ffbe..b514c2b 100644
--- a/src/tint/writer/hlsl/generator.cc
+++ b/src/tint/writer/hlsl/generator.cc
@@ -29,6 +29,10 @@
 
 Result Generate(const Program* program, const Options& options) {
     Result result;
+    if (!program->IsValid()) {
+        result.error = "input program is not valid";
+        return result;
+    }
 
     // Sanitize the program.
     auto sanitized_result = Sanitize(program, options);
diff --git a/src/tint/writer/hlsl/generator_impl_test.cc b/src/tint/writer/hlsl/generator_impl_test.cc
index 460b202..a1e0edb 100644
--- a/src/tint/writer/hlsl/generator_impl_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_test.cc
@@ -19,6 +19,15 @@
 
 using HlslGeneratorImplTest = TestHelper;
 
+TEST_F(HlslGeneratorImplTest, InvalidProgram) {
+    Diagnostics().add_error(diag::System::Writer, "make the program invalid");
+    ASSERT_FALSE(IsValid());
+    auto program = std::make_unique<Program>(std::move(*this));
+    ASSERT_FALSE(program->IsValid());
+    auto result = Generate(program.get(), Options{});
+    EXPECT_EQ(result.error, "input program is not valid");
+}
+
 TEST_F(HlslGeneratorImplTest, Generate) {
     Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
 
diff --git a/src/tint/writer/msl/generator.cc b/src/tint/writer/msl/generator.cc
index 6d09a86..5cd9ac8 100644
--- a/src/tint/writer/msl/generator.cc
+++ b/src/tint/writer/msl/generator.cc
@@ -31,6 +31,10 @@
 
 Result Generate(const Program* program, const Options& options) {
     Result result;
+    if (!program->IsValid()) {
+        result.error = "input program is not valid";
+        return result;
+    }
 
     // Sanitize the program.
     auto sanitized_result = Sanitize(program, options);
diff --git a/src/tint/writer/msl/generator_impl_test.cc b/src/tint/writer/msl/generator_impl_test.cc
index b5af8e4..dd90715 100644
--- a/src/tint/writer/msl/generator_impl_test.cc
+++ b/src/tint/writer/msl/generator_impl_test.cc
@@ -22,6 +22,15 @@
 
 using MslGeneratorImplTest = TestHelper;
 
+TEST_F(MslGeneratorImplTest, InvalidProgram) {
+    Diagnostics().add_error(diag::System::Writer, "make the program invalid");
+    ASSERT_FALSE(IsValid());
+    auto program = std::make_unique<Program>(std::move(*this));
+    ASSERT_FALSE(program->IsValid());
+    auto result = Generate(program.get(), Options{});
+    EXPECT_EQ(result.error, "input program is not valid");
+}
+
 TEST_F(MslGeneratorImplTest, Generate) {
     Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
          ast::AttributeList{
diff --git a/src/tint/writer/spirv/builder_test.cc b/src/tint/writer/spirv/builder_test.cc
index f2475c0..3548f9a 100644
--- a/src/tint/writer/spirv/builder_test.cc
+++ b/src/tint/writer/spirv/builder_test.cc
@@ -20,6 +20,15 @@
 
 using BuilderTest = TestHelper;
 
+TEST_F(BuilderTest, InvalidProgram) {
+    Diagnostics().add_error(diag::System::Writer, "make the program invalid");
+    ASSERT_FALSE(IsValid());
+    auto program = std::make_unique<Program>(std::move(*this));
+    ASSERT_FALSE(program->IsValid());
+    auto result = Generate(program.get(), Options{});
+    EXPECT_EQ(result.error, "input program is not valid");
+}
+
 TEST_F(BuilderTest, TracksIdBounds) {
     spirv::Builder& b = Build();
 
diff --git a/src/tint/writer/spirv/generator.cc b/src/tint/writer/spirv/generator.cc
index fa67827..93ac6e1 100644
--- a/src/tint/writer/spirv/generator.cc
+++ b/src/tint/writer/spirv/generator.cc
@@ -26,6 +26,10 @@
 
 Result Generate(const Program* program, const Options& options) {
     Result result;
+    if (!program->IsValid()) {
+        result.error = "input program is not valid";
+        return result;
+    }
 
     // Sanitize the program.
     auto sanitized_result = Sanitize(program, options);