Fix crash with boolean vectors in is_constant<T>.

Previously, we assumed that if a vector in `is_constant` was not made of
floats, it must be made of integers. This ignores that boolean vectors
also exist. The original code would abort when `getIVecComponent` was
called on a bool vector.

There is another bug here--arithmetic operators on bool types should be
disallowed entirely. That will be addressed in later CLs.

Change-Id: I78781d839abde9376917fd92f2fe6311a1a58b02
Bug: oss-fuzz:27808
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/338055
Auto-Submit: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
John Stiles 2020-11-24 12:04:47 -05:00 committed by Skia Commit-Bot
parent 7512507050
commit bc75ebb1af
6 changed files with 38 additions and 9 deletions

View File

@ -84,6 +84,7 @@ sksl_error_tests = [
"$_tests/sksl/errors/BitShiftFloat.sksl",
"$_tests/sksl/errors/BitShiftFloatMatrix.sksl",
"$_tests/sksl/errors/BitShiftFloatVector.sksl",
"$_tests/sksl/errors/BooleanArithmetic.sksl",
"$_tests/sksl/errors/BreakOutsideLoop.sksl",
"$_tests/sksl/errors/CallNonFunction.sksl",
"$_tests/sksl/errors/CanExitWithoutReturningValue.sksl",

View File

@ -663,23 +663,25 @@ static bool is_constant(const Expression& expr, T value) {
const Constructor& constructor = expr.as<Constructor>();
if (constructor.isCompileTimeConstant()) {
const Type& constructorType = constructor.type();
bool isFloat = constructorType.columns() > 1
? constructorType.componentType().isFloat()
: constructorType.isFloat();
switch (constructorType.typeKind()) {
case Type::TypeKind::kVector:
for (int i = 0; i < constructorType.columns(); ++i) {
if (isFloat) {
if (constructor.componentType().isFloat()) {
for (int i = 0; i < constructorType.columns(); ++i) {
if (constructor.getFVecComponent(i) != value) {
return false;
}
} else {
}
return true;
} else if (constructor.componentType().isInteger()) {
for (int i = 0; i < constructorType.columns(); ++i) {
if (constructor.getIVecComponent(i) != value) {
return false;
}
}
return true;
}
return true;
// Other types (e.g. boolean) might occur, but aren't supported here.
return false;
case Type::TypeKind::kScalar:
SkASSERT(constructor.arguments().size() == 1);

View File

@ -103,7 +103,7 @@ ResultType Constructor::getVecComponent(int index) const {
if (current + constructor.type().columns() > index) {
// We've found a constructor that overlaps the proper argument. Descend into
// it, honoring the type.
return constructor.type().componentType().isFloat()
return constructor.componentType().isFloat()
? ResultType(constructor.getVecComponent<SKSL_FLOAT>(index - current))
: ResultType(constructor.getVecComponent<SKSL_INT>(index - current));
}

View File

@ -75,6 +75,12 @@ public:
return result;
}
const Type& componentType() const {
// Returns `float` for constructors of type `float(...)` or `floatN(...)`.
const Type& type = this->type();
return type.columns() == 1 ? type : type.componentType();
}
bool isCompileTimeConstant() const override {
for (const std::unique_ptr<Expression>& arg: this->arguments()) {
if (!arg->isCompileTimeConstant()) {
@ -98,13 +104,17 @@ public:
template <typename resultType>
resultType getVecComponent(int index) const;
/**
* For a literal vector expression, return the float value of the n'th vector component. It is
* an error to call this method on an expression which is not a vector of FloatLiterals.
*/
SKSL_FLOAT getFVecComponent(int n) const override {
return this->getVecComponent<SKSL_FLOAT>(n);
}
/**
* For a literal vector expression, return the integer value of the n'th vector component. It is
* an error to call this method on an expression which is not a literal vector.
* an error to call this method on an expression which is not a vector of IntLiterals.
*/
SKSL_INT getIVecComponent(int n) const override {
return this->getVecComponent<SKSL_INT>(n);

View File

@ -0,0 +1,13 @@
bool2 add_boolean_vec() { return bool2(false, false) + bool2(true, true); }
bool2 sub_boolean_vec() { return bool2(false, false) - bool2(true, true); }
bool2 mul_boolean_vec() { return bool2(false, false) * bool2(true, true); }
bool2 div_boolean_vec() { return bool2(false, false) / bool2(true, true); }
bool2 mod_boolean_vec() { return bool2(false, false) % bool2(true, true); }
void main() {
add_boolean_vec();
sub_boolean_vec();
mul_boolean_vec();
div_boolean_vec();
mod_boolean_vec();
}

View File

@ -0,0 +1,3 @@
void main() {
}