Fixed SkSL use-after-free fuzzer bug and added defensive code to catch such problems in the future.
Bug: skia:7558 Change-Id: I5098c0ed08f2328828969e819db7785270b26656 Reviewed-on: https://skia-review.googlesource.com/111460 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
parent
a7f320507d
commit
68dd2c1fa0
@ -286,6 +286,9 @@ std::unique_ptr<VarDeclarations> IRGenerator::convertVarDeclarations(const ASTVa
|
||||
return nullptr;
|
||||
}
|
||||
value = this->coerce(std::move(value), *type);
|
||||
if (!value) {
|
||||
return nullptr;
|
||||
}
|
||||
var->fWriteCount = 1;
|
||||
var->fInitialValue = value.get();
|
||||
}
|
||||
@ -761,7 +764,8 @@ void IRGenerator::convertFunction(const ASTFunction& f) {
|
||||
|
||||
std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTInterfaceBlock& intf) {
|
||||
std::shared_ptr<SymbolTable> old = fSymbolTable;
|
||||
AutoSymbolTable table(this);
|
||||
this->pushSymbolTable();
|
||||
std::shared_ptr<SymbolTable> symbols = fSymbolTable;
|
||||
std::vector<Type::Field> fields;
|
||||
bool haveRuntimeArray = false;
|
||||
bool foundRTAdjust = false;
|
||||
@ -804,6 +808,7 @@ std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTInte
|
||||
}
|
||||
}
|
||||
}
|
||||
this->popSymbolTable();
|
||||
Type* type = new Type(intf.fOffset, intf.fTypeName, fields);
|
||||
old->takeOwnership(type);
|
||||
std::vector<std::unique_ptr<Expression>> sizes;
|
||||
@ -826,11 +831,11 @@ std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTInte
|
||||
name += "[]";
|
||||
}
|
||||
type = new Type(name, Type::kArray_Kind, *type, (int) count);
|
||||
fSymbolTable->takeOwnership((Type*) type);
|
||||
symbols->takeOwnership((Type*) type);
|
||||
sizes.push_back(std::move(converted));
|
||||
} else {
|
||||
type = new Type(type->name() + "[]", Type::kArray_Kind, *type, -1);
|
||||
fSymbolTable->takeOwnership((Type*) type);
|
||||
symbols->takeOwnership((Type*) type);
|
||||
sizes.push_back(nullptr);
|
||||
}
|
||||
}
|
||||
@ -858,7 +863,7 @@ std::unique_ptr<InterfaceBlock> IRGenerator::convertInterfaceBlock(const ASTInte
|
||||
intf.fTypeName,
|
||||
intf.fInstanceName,
|
||||
std::move(sizes),
|
||||
fSymbolTable));
|
||||
symbols));
|
||||
}
|
||||
|
||||
void IRGenerator::getConstantInt(const Expression& value, int64_t* out) {
|
||||
|
@ -29,6 +29,8 @@ struct Symbol : public IRNode {
|
||||
, fKind(kind)
|
||||
, fName(name) {}
|
||||
|
||||
virtual ~Symbol() {}
|
||||
|
||||
Kind fKind;
|
||||
StringFragment fName;
|
||||
|
||||
|
@ -37,7 +37,15 @@ struct Variable : public Symbol {
|
||||
, fStorage(storage)
|
||||
, fInitialValue(initialValue)
|
||||
, fReadCount(0)
|
||||
, fWriteCount(0) {}
|
||||
, fWriteCount(initialValue ? 1 : 0) {}
|
||||
|
||||
~Variable() override {
|
||||
// can't destroy a variable while there are remaining references to it
|
||||
if (fInitialValue) {
|
||||
--fWriteCount;
|
||||
}
|
||||
ASSERT(!fReadCount && !fWriteCount);
|
||||
}
|
||||
|
||||
virtual String description() const override {
|
||||
return fModifiers.description() + fType.fName + " " + fName;
|
||||
|
@ -45,6 +45,9 @@ struct VariableReference : public Expression {
|
||||
}
|
||||
|
||||
~VariableReference() override {
|
||||
if (fRefKind != kRead_RefKind) {
|
||||
fVariable.fWriteCount--;
|
||||
}
|
||||
if (fRefKind != kWrite_RefKind) {
|
||||
fVariable.fReadCount--;
|
||||
}
|
||||
|
@ -489,4 +489,12 @@ DEF_TEST(SkSLStaticSwitch, r) {
|
||||
"error: 1: static switch contains non-static conditional break\n1 error\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLInterfaceBlockScope, r) {
|
||||
test_failure(r,
|
||||
"uniform testBlock {"
|
||||
"float x;"
|
||||
"} test[x];",
|
||||
"error: 1: unknown identifier 'x'\n1 error\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -32,10 +32,12 @@ static void test_failure(skiatest::Reporter* r, const char* src, const char* err
|
||||
|
||||
DEF_TEST(SkSLBadOffset, r) {
|
||||
test_failure(r,
|
||||
"struct Bad { layout (offset = 5) int x; } bad; void main() { bad.x = 5; }",
|
||||
"struct Bad { layout (offset = 5) int x; } bad; void main() { bad.x = 5; "
|
||||
"sk_FragColor.r = float(bad.x); }",
|
||||
"error: 1: offset of field 'x' must be a multiple of 4\n1 error\n");
|
||||
test_failure(r,
|
||||
"struct Bad { int x; layout (offset = 0) int y; } bad; void main() { bad.x = 5; }",
|
||||
"struct Bad { int x; layout (offset = 0) int y; } bad; void main() { bad.x = 5; "
|
||||
"sk_FragColor.r = float(bad.x); }",
|
||||
"error: 1: offset of field 'y' must be at least 4\n1 error\n");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user