Validate function return and parameter types in IR generator

Prevents invalid types from making it to the pipeline stage generator,
when it's too late to do anything.

Bug: oss-fuzz:24542
Change-Id: I8b6fa2afd5d586b0e60bea82e0ec4f3ae43de973
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/307656
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index ab553be..235755b 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -212,7 +212,8 @@
 GrGLSLFragmentProcessor* GrSkSLFP::onCreateGLSLInstance() const {
     // Note: This is actually SkSL (again) but with inline format specifiers.
     SkSL::PipelineStageArgs args;
-    fEffect->toPipelineStage(fInputs->data(), fShaderCaps.get(), fShaderErrorHandler, &args);
+    SkAssertResult(fEffect->toPipelineStage(fInputs->data(), fShaderCaps.get(), fShaderErrorHandler,
+                                            &args));
     return new GrGLSLSkSLFP(std::move(args));
 }
 
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index e41967a..36b9391 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -1794,7 +1794,7 @@
     }
     write_stringstream(fExtraFunctions, *rawOut);
     write_stringstream(body, *rawOut);
-    return true;
+    return 0 == fErrors.errorCount();
 }
 
 }
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 6c9ff18..1e240a5 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -13,6 +13,7 @@
 
 #include "src/sksl/SkSLCompiler.h"
 #include "src/sksl/SkSLParser.h"
+#include "src/sksl/SkSLUtil.h"
 #include "src/sksl/ir/SkSLBinaryExpression.h"
 #include "src/sksl/ir/SkSLBoolLiteral.h"
 #include "src/sksl/ir/SkSLBreakStatement.h"
@@ -832,7 +833,17 @@
     if (!returnType) {
         return;
     }
-    if (returnType->nonnullable() == *fContext.fFragmentProcessor_Type) {
+    auto type_is_allowed = [&](const Type* t) {
+#if defined(SKSL_STANDALONE)
+        return true;
+#else
+        GrSLType unusedSLType;
+        return fKind != Program::kPipelineStage_Kind ||
+               type_to_grsltype(fContext, *t, &unusedSLType);
+#endif
+    };
+    if (returnType->nonnullable() == *fContext.fFragmentProcessor_Type ||
+        !type_is_allowed(returnType)) {
         fErrors.error(f.fOffset,
                       "functions may not return type '" + returnType->displayName() + "'");
         return;
@@ -848,12 +859,6 @@
         if (!type) {
             return;
         }
-        // Only the (builtin) declarations of 'sample' are allowed to have FP parameters
-        if (type->nonnullable() == *fContext.fFragmentProcessor_Type && !fIsBuiltinCode) {
-            fErrors.error(param.fOffset,
-                          "parameters of type '" + type->displayName() + "' not allowed");
-            return;
-        }
         for (int j = (int) pd.fSizeCount; j >= 1; j--) {
             int size = (param.begin() + j)->getInt();
             String name = type->name() + "[" + to_string(size) + "]";
@@ -863,6 +868,13 @@
                                                                                   *type,
                                                                                   size)));
         }
+        // Only the (builtin) declarations of 'sample' are allowed to have FP parameters
+        if ((type->nonnullable() == *fContext.fFragmentProcessor_Type && !fIsBuiltinCode) ||
+            !type_is_allowed(type)) {
+            fErrors.error(param.fOffset,
+                          "parameters of type '" + type->displayName() + "' not allowed");
+            return;
+        }
         StringFragment name = pd.fName;
         const Variable* var = (const Variable*) fSymbolTable->takeOwnership(
                          std::unique_ptr<const Symbol>(new Variable(param.fOffset,
diff --git a/src/sksl/SkSLPipelineStageCodeGenerator.cpp b/src/sksl/SkSLPipelineStageCodeGenerator.cpp
index ababa98..acbeed0 100644
--- a/src/sksl/SkSLPipelineStageCodeGenerator.cpp
+++ b/src/sksl/SkSLPipelineStageCodeGenerator.cpp
@@ -177,26 +177,6 @@
     INHERITED::writeSwitchStatement(s);
 }
 
-static GrSLType glsltype(const Context& context, const Type& type) {
-    if (type == *context.fFloat_Type)    { return kFloat_GrSLType;    }
-    if (type == *context.fHalf_Type)     { return kHalf_GrSLType;     }
-    if (type == *context.fFloat2_Type)   { return kFloat2_GrSLType;   }
-    if (type == *context.fHalf2_Type)    { return kHalf2_GrSLType;    }
-    if (type == *context.fFloat3_Type)   { return kFloat3_GrSLType;   }
-    if (type == *context.fHalf3_Type)    { return kHalf3_GrSLType;    }
-    if (type == *context.fFloat4_Type)   { return kFloat4_GrSLType;   }
-    if (type == *context.fHalf4_Type)    { return kHalf4_GrSLType;    }
-    if (type == *context.fFloat2x2_Type) { return kFloat2x2_GrSLType; }
-    if (type == *context.fHalf2x2_Type)  { return kHalf2x2_GrSLType;  }
-    if (type == *context.fFloat3x3_Type) { return kFloat3x3_GrSLType; }
-    if (type == *context.fHalf3x3_Type)  { return kHalf3x3_GrSLType;  }
-    if (type == *context.fFloat4x4_Type) { return kFloat4x4_GrSLType; }
-    if (type == *context.fHalf4x4_Type)  { return kHalf4x4_GrSLType;  }
-    if (type == *context.fVoid_Type)     { return kVoid_GrSLType;     }
-    SK_ABORT("Unsupported type");
-}
-
-
 void PipelineStageCodeGenerator::writeFunction(const FunctionDefinition& f) {
     fFunctionHeader = "";
     OutputStream* oldOut = fOut;
@@ -219,10 +199,18 @@
     } else {
         const FunctionDeclaration& decl = f.fDeclaration;
         Compiler::GLSLFunction result;
-        result.fReturnType = glsltype(fContext, decl.fReturnType);
+        if (!type_to_grsltype(fContext, decl.fReturnType, &result.fReturnType)) {
+            fErrors.error(f.fOffset, "unsupported return type");
+            return;
+        }
         result.fName = decl.fName;
         for (const Variable* v : decl.fParameters) {
-            result.fParameters.emplace_back(v->fName, glsltype(fContext, v->fType));
+            GrSLType paramSLType;
+            if (!type_to_grsltype(fContext, v->fType, &paramSLType)) {
+                fErrors.error(v->fOffset, "unsupported parameter type");
+                return;
+            }
+            result.fParameters.emplace_back(v->fName, paramSLType);
         }
         for (const auto& s : ((Block&) *f.fBody).fStatements) {
             this->writeStatement(*s);
diff --git a/src/sksl/SkSLUtil.cpp b/src/sksl/SkSLUtil.cpp
index ae9157b..dca493e 100644
--- a/src/sksl/SkSLUtil.cpp
+++ b/src/sksl/SkSLUtil.cpp
@@ -7,6 +7,7 @@
 
 #include "src/sksl/SkSLUtil.h"
 
+#include "src/sksl/SkSLContext.h"
 #include "src/sksl/SkSLStringStream.h"
 
 #ifndef __STDC_FORMAT_MACROS
@@ -73,4 +74,25 @@
     }
 }
 
+#if !defined(SKSL_STANDALONE)
+bool type_to_grsltype(const Context& context, const Type& type, GrSLType* outType) {
+    if (type == *context.fFloat_Type)    { *outType = kFloat_GrSLType;    return true; }
+    if (type == *context.fHalf_Type)     { *outType = kHalf_GrSLType;     return true; }
+    if (type == *context.fFloat2_Type)   { *outType = kFloat2_GrSLType;   return true; }
+    if (type == *context.fHalf2_Type)    { *outType = kHalf2_GrSLType;    return true; }
+    if (type == *context.fFloat3_Type)   { *outType = kFloat3_GrSLType;   return true; }
+    if (type == *context.fHalf3_Type)    { *outType = kHalf3_GrSLType;    return true; }
+    if (type == *context.fFloat4_Type)   { *outType = kFloat4_GrSLType;   return true; }
+    if (type == *context.fHalf4_Type)    { *outType = kHalf4_GrSLType;    return true; }
+    if (type == *context.fFloat2x2_Type) { *outType = kFloat2x2_GrSLType; return true; }
+    if (type == *context.fHalf2x2_Type)  { *outType = kHalf2x2_GrSLType;  return true; }
+    if (type == *context.fFloat3x3_Type) { *outType = kFloat3x3_GrSLType; return true; }
+    if (type == *context.fHalf3x3_Type)  { *outType = kHalf3x3_GrSLType;  return true; }
+    if (type == *context.fFloat4x4_Type) { *outType = kFloat4x4_GrSLType; return true; }
+    if (type == *context.fHalf4x4_Type)  { *outType = kHalf4x4_GrSLType;  return true; }
+    if (type == *context.fVoid_Type)     { *outType = kVoid_GrSLType;     return true; }
+    return false;
+}
+#endif
+
 } // namespace
diff --git a/src/sksl/SkSLUtil.h b/src/sksl/SkSLUtil.h
index 552a99b..1c316a2 100644
--- a/src/sksl/SkSLUtil.h
+++ b/src/sksl/SkSLUtil.h
@@ -17,6 +17,7 @@
 
 #ifndef SKSL_STANDALONE
 #include "include/core/SkTypes.h"
+#include "include/private/GrTypesPriv.h"
 #if SK_SUPPORT_GPU
 #include "include/gpu/GrContextOptions.h"
 #include "src/gpu/GrShaderCaps.h"
@@ -27,8 +28,10 @@
 
 namespace SkSL {
 
+class Context;
 class OutputStream;
 class StringStream;
+class Type;
 
 #if defined(SKSL_STANDALONE) || !SK_SUPPORT_GPU
 
@@ -401,6 +404,10 @@
 };
 #endif
 
+#if !defined(SKSL_STANDALONE)
+bool type_to_grsltype(const Context& context, const Type& type, GrSLType* outType);
+#endif
+
 void write_stringstream(const StringStream& d, OutputStream& out);
 
 // Returns true if op is '=' or any compound assignment operator ('+=', '-=', etc.)