Fix assertion when calling a built-in function at global scope.
The fuzzer invented a much more elaborate example, but I was able to
winnow it down to a simple otherwise-normal test case. This also fixes
a latent DSL bug; DSL functions were not updating the list of referenced
intrinsics, so the compiler might emit finished programs that called
built-in functions that didn't exist in the code.
Change-Id: I095bb566b9db9f87cbe9460732c300b7973eb112
Bug: oss-fuzz:37659
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/442325
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index cd5e239..5206457 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -640,8 +640,11 @@
std::vector<const Variable*>(),
fContext.fTypes.fVoid.get(),
fIsBuiltinCode));
- auto invokeDef = std::make_unique<FunctionDefinition>(/*offset=*/-1, invokeDecl, fIsBuiltinCode,
- std::move(main));
+ IntrinsicSet referencedIntrinsics;
+ main = this->finalizeFunction(*invokeDecl, std::move(main), &referencedIntrinsics);
+ auto invokeDef = std::make_unique<FunctionDefinition>(/*offset=*/-1, invokeDecl,
+ fIsBuiltinCode, std::move(main),
+ std::move(referencedIntrinsics));
invokeDecl->setDefinition(invokeDef.get());
fProgramElements->push_back(std::move(invokeDef));
@@ -759,12 +762,15 @@
}
std::unique_ptr<Block> IRGenerator::finalizeFunction(const FunctionDeclaration& funcDecl,
- std::unique_ptr<Block> body) {
+ std::unique_ptr<Block> body,
+ IntrinsicSet* referencedIntrinsics) {
class Finalizer : public ProgramWriter {
public:
- Finalizer(IRGenerator* irGenerator, const FunctionDeclaration* function)
+ Finalizer(IRGenerator* irGenerator, const FunctionDeclaration* function,
+ IntrinsicSet* referencedIntrinsics)
: fIRGenerator(irGenerator)
- , fFunction(function) {}
+ , fFunction(function)
+ , fReferencedIntrinsics(referencedIntrinsics) {}
~Finalizer() override {
SkASSERT(!fBreakableLevel);
@@ -776,8 +782,13 @@
}
bool visitExpression(Expression& expr) override {
- // Do not recurse into expressions.
- return false;
+ if (expr.is<FunctionCall>()) {
+ const FunctionDeclaration& func = expr.as<FunctionCall>().function();
+ if (func.isBuiltin() && func.definition()) {
+ fReferencedIntrinsics->insert(&func);
+ }
+ }
+ return INHERITED::visitExpression(expr);
}
bool visitStatement(Statement& stmt) override {
@@ -850,6 +861,8 @@
private:
IRGenerator* fIRGenerator;
const FunctionDeclaration* fFunction;
+ // which intrinsics have we encountered in this function
+ IntrinsicSet* fReferencedIntrinsics;
// how deeply nested we are in breakable constructs (for, do, switch).
int fBreakableLevel = 0;
// how deeply nested we are in continuable constructs (for, do).
@@ -868,7 +881,7 @@
body->children().push_back(this->getNormalizeSkPositionCode());
}
- Finalizer finalizer{this, &funcDecl};
+ Finalizer finalizer{this, &funcDecl, referencedIntrinsics};
finalizer.visitStatement(*body);
if (Analysis::CanExitWithoutReturningValue(funcDecl, *body)) {
@@ -879,9 +892,6 @@
}
void IRGenerator::convertFunction(const ASTNode& f) {
- SkASSERT(fReferencedIntrinsics.empty());
- SK_AT_SCOPE_EXIT(fReferencedIntrinsics.clear());
-
auto iter = f.begin();
const Type* returnType = this->convertType(*(iter++), /*allowVoid=*/true);
if (returnType == nullptr) {
@@ -954,9 +964,10 @@
if (!body) {
return;
}
- body = this->finalizeFunction(*decl, std::move(body));
+ IntrinsicSet referencedIntrinsics;
+ body = this->finalizeFunction(*decl, std::move(body), &referencedIntrinsics);
auto result = std::make_unique<FunctionDefinition>(
- f.fOffset, decl, fIsBuiltinCode, std::move(body), std::move(fReferencedIntrinsics));
+ f.fOffset, decl, fIsBuiltinCode, std::move(body), std::move(referencedIntrinsics));
decl->setDefinition(result.get());
result->setSource(&f);
fProgramElements->push_back(std::move(result));
@@ -1287,9 +1298,6 @@
if (function.intrinsicKind() == k_dFdy_IntrinsicKind) {
fInputs.fUseFlipRTUniform = true;
}
- if (function.definition()) {
- fReferencedIntrinsics.insert(&function);
- }
if (!fIsBuiltinCode && fIntrinsics) {
this->copyIntrinsicIfNeeded(function);
}