Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Const arrays, and fuzzing of array constructors #883

Merged
merged 1 commit into from
Feb 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public class ArrayType extends UnqualifiedType {
private ArrayInfo arrayInfo;

public ArrayType(Type baseType, ArrayInfo arrayInfo) {
if (baseType instanceof QualifiedType) {
throw new IllegalArgumentException("Qualifiers should be applied to an array type, not to "
+ "the array's base type.");
}
this.baseType = baseType;
this.arrayInfo = arrayInfo;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package com.graphicsfuzz.common.ast.visitors;

import com.graphicsfuzz.common.ast.IAstNode;
import com.graphicsfuzz.common.ast.IParentMap;
import com.graphicsfuzz.common.ast.TranslationUnit;
import com.graphicsfuzz.common.ast.decl.ArrayInfo;
import com.graphicsfuzz.common.ast.decl.Declaration;
Expand Down Expand Up @@ -555,8 +553,11 @@ private Pair<List<String>, List<Type>> getMembers(Member_listContext memberListC
if (declarators.struct_declarator().array_specifier() == null) {
fieldTypes.addFirst(baseType);
} else {
fieldTypes.addFirst(new ArrayType(baseType,
getArrayInfo(declarators.struct_declarator().array_specifier())));
final ArrayType arrayType = new ArrayType(baseType.getWithoutQualifiers(),
getArrayInfo(declarators.struct_declarator().array_specifier()));
fieldTypes.addFirst(baseType instanceof QualifiedType
? new QualifiedType(arrayType, ((QualifiedType) baseType).getQualifiers())
: arrayType);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import com.graphicsfuzz.common.ast.stmt.ForStmt;
import com.graphicsfuzz.common.ast.stmt.WhileStmt;
import com.graphicsfuzz.common.ast.type.ArrayType;
import com.graphicsfuzz.common.ast.type.QualifiedType;
import com.graphicsfuzz.common.ast.type.StructDefinitionType;
import com.graphicsfuzz.common.ast.type.Type;
import com.graphicsfuzz.common.ast.visitors.StandardVisitor;
import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -125,8 +127,18 @@ public void visitFunctionPrototype(FunctionPrototype functionPrototype) {
if (!addEncounteredParametersToScope || p.getName() == null) {
continue;
}
Type type;
if (p.getArrayInfo() == null) {
type = p.getType();
} else {
final ArrayType arrayType = new ArrayType(p.getType().getWithoutQualifiers(),
p.getArrayInfo());
type = p.getType() instanceof QualifiedType
? new QualifiedType(arrayType, ((QualifiedType) p.getType()).getQualifiers())
: arrayType;
}
currentScope.add(p.getName(),
p.getArrayInfo() == null ? p.getType() : new ArrayType(p.getType(), p.getArrayInfo()),
type,
Optional.of(p));
}
}
Expand All @@ -147,10 +159,45 @@ public void visitVariablesDeclaration(VariablesDeclaration variablesDeclaration)
// Visit the declInfo both before and after adding it to the current scope, to give
// subclasses the flexibility to examine both cases.
visitVariableDeclInfo(declInfo);

// We record a type for declInfo.name. If declInfo is not an array, this is just the base
// type for the variables declaration. But if declInfo *is* an array, we need to promote
// any qualifiers applied to the base type to apply to the whole array. That is, we want to
// give A in:
//
// const int A[3] = ...;
//
// the type QualifiedType(ArrayType(int, 3), const)
//
// not:
//
// ArrayType(QualifiedType(int, const), 3)

// Get the base type for the variables declaration.
final Type variablesDeclarationBaseType = variablesDeclaration.getBaseType();

// Now get a type for declInfo depending on whether or not it is an array.
Type declInfoType;
if (declInfo.hasArrayInfo()) {
// Make an array type using a qualifier-free version of the variables declaration base type.
final ArrayType arrayType = new ArrayType(variablesDeclarationBaseType
.getWithoutQualifiers(),
declInfo.getArrayInfo());
// If the variables declaration base type had qualifiers, apply these to the entire array.
if (variablesDeclarationBaseType instanceof QualifiedType) {
declInfoType = new QualifiedType(arrayType,
((QualifiedType) variablesDeclarationBaseType).getQualifiers());
} else {
declInfoType = arrayType;
}
} else {
// This is the easy case: no array, so the type is just the base type for the variables
// declaration.
declInfoType = variablesDeclarationBaseType;
}

currentScope.add(declInfo.getName(),
declInfo.getArrayInfo() == null
? variablesDeclaration.getBaseType()
: new ArrayType(variablesDeclaration.getBaseType(), declInfo.getArrayInfo()),
declInfoType,
Optional.empty(),
declInfo, variablesDeclaration);
visitVariableDeclInfoAfterAddedToScope(declInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,25 @@ public void testParseAndPrintStructs() throws Exception {
)));
}

@Test
public void testParseAndPrintArrayParameter() throws Exception {
final String program = "void foo(int A[2])\n"
+ "{\n"
+ "}\n";
assertEquals(program, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(program
)));
}

@Test
public void testParseAndPrintArrayVariable() throws Exception {
final String program = "void main()\n"
+ "{\n"
+ " int A[2] = int[2](1, 2);\n"
+ "}\n";
assertEquals(program, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(program
)));
}

@Test
public void testParseAndPrintStructs2() throws Exception {
// This checks exact layout, so will require maintenance if things change.
Expand Down
32 changes: 32 additions & 0 deletions ast/src/test/java/com/graphicsfuzz/common/typing/TyperTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import com.graphicsfuzz.common.ast.TranslationUnit;
import com.graphicsfuzz.common.ast.decl.FunctionPrototype;
import com.graphicsfuzz.common.ast.decl.Initializer;
import com.graphicsfuzz.common.ast.decl.ParameterDecl;
import com.graphicsfuzz.common.ast.decl.VariableDeclInfo;
import com.graphicsfuzz.common.ast.decl.VariablesDeclaration;
import com.graphicsfuzz.common.ast.expr.ArrayIndexExpr;
import com.graphicsfuzz.common.ast.expr.BinOp;
import com.graphicsfuzz.common.ast.expr.BinaryExpr;
Expand All @@ -39,11 +42,14 @@
import com.graphicsfuzz.common.ast.expr.TypeConstructorExpr;
import com.graphicsfuzz.common.ast.expr.UnaryExpr;
import com.graphicsfuzz.common.ast.expr.VariableIdentifierExpr;
import com.graphicsfuzz.common.ast.type.ArrayType;
import com.graphicsfuzz.common.ast.type.BasicType;
import com.graphicsfuzz.common.ast.type.QualifiedType;
import com.graphicsfuzz.common.ast.type.Type;
import com.graphicsfuzz.common.ast.type.TypeQualifier;
import com.graphicsfuzz.common.ast.type.VoidType;
import com.graphicsfuzz.common.ast.visitors.StandardVisitor;
import com.graphicsfuzz.common.ast.visitors.UnsupportedLanguageFeatureException;
import com.graphicsfuzz.common.glslversion.ShadingLanguageVersion;
import com.graphicsfuzz.common.util.GlslParserException;
import com.graphicsfuzz.common.util.ShaderKind;
Expand Down Expand Up @@ -685,6 +691,32 @@ public void visitFunctionCallExpr(FunctionCallExpr functionCallExpr) {
}.visit(tu);
}

@Test
public void testConstArrayCorrectlyTyped() throws Exception {
TranslationUnit tu = ParseHelper.parse("#version 310 es\n"
+ "int main() {\n"
+ " const int A[2] = int[2](1, 2);\n"
+ " A;\n"
+ "}\n");
new NullCheckTyper(tu) {
@Override
public void visitVariableIdentifierExpr(VariableIdentifierExpr variableIdentifierExpr) {
super.visitVariableIdentifierExpr(variableIdentifierExpr);
assert(variableIdentifierExpr.getName().equals("A"));
final Type type = lookupType(variableIdentifierExpr);
assertTrue(type.hasQualifier(TypeQualifier.CONST));
assertTrue(type.getWithoutQualifiers() instanceof ArrayType);
final ArrayType withoutQualifiers = (ArrayType) type.getWithoutQualifiers();
assertSame(withoutQualifiers.getBaseType(), BasicType.INT);
try {
assertEquals(2, withoutQualifiers.getArrayInfo().getConstantSize().intValue());
} catch (UnsupportedLanguageFeatureException exception) {
fail();
}
}
};
}

private void checkComputeShaderBuiltin(String builtin, String builtinConstant, BasicType baseType,
TypeQualifier qualifier) throws IOException, ParseTimeoutException, InterruptedException,
GlslParserException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import com.graphicsfuzz.generator.fuzzer.templates.IExprTemplate;
import com.graphicsfuzz.generator.fuzzer.templates.VariableIdentifierExprTemplate;
import com.graphicsfuzz.generator.util.GenerationParams;
import com.graphicsfuzz.util.Constants;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -174,16 +175,7 @@ private Expr makeExpr(Type targetType, boolean isLValue, boolean constContext, f
}
if (targetType instanceof ArrayType) {
// TODO: we should use in-scope variables and functions to make arrays
if (shadingLanguageVersion.supportedArrayConstructors()) {
ArrayType arrayType = (ArrayType) targetType;
List<Expr> args = new ArrayList<>();
for (int i = 0; i < arrayType.getArrayInfo().getConstantSize(); i++) {
args.add(makeExpr(arrayType.getBaseType(), isLValue, constContext, depth + 1));
}
return new ArrayConstructorExpr((ArrayType) stripQualifiers(targetType), args);
} else {
throw new FuzzedIntoACornerException();
}
return generateArrayConstructor(targetType, isLValue, constContext, depth);
}
if (targetType instanceof StructNameType) {
final String structName = ((StructNameType) targetType).getName();
Expand All @@ -201,6 +193,64 @@ private Expr makeExpr(Type targetType, boolean isLValue, boolean constContext, f

}

private Expr generateArrayConstructor(Type targetType, boolean isLValue, boolean constContext,
int depth) {
if (shadingLanguageVersion.supportedArrayConstructors()) {
final ArrayType arrayType = (ArrayType) targetType;

// We want to generate an expression for each array index. But if the array is
// large, there is a high chance we will fail to generate expressions for some
// indices, leading to a "fuzzed into a corner" exception.
//
// What we do is try SIZE_OF_ARRAY times to generate an expression, storing all the
// expressions we successfully generate. If we fail to generate *any* then we throw a
// "fuzzed into a corner" exception. Otherwise, we re-use the set of expressions we did
// manage to generate as much as needed in order to get the required number of expressions.
//
// However, because SIZE_OF_ARRAY could be very large, we bound the number of expressions
// we generate by a constant, and resort to re-use to generate very large arrays.

// These are the expressions we will initially generate.
final List<Expr> generatedExprs = new ArrayList<>();
for (int i = 0; i < Math.min(Constants.MAX_GENERATED_EXPRESSIONS_FOR_ARRAY_CONSTRUCTOR,
arrayType.getArrayInfo().getConstantSize()); i++) {
try {
generatedExprs.add(makeExpr(arrayType.getBaseType(), isLValue, constContext, depth + 1));
} catch (FuzzedIntoACornerException exception) {
// Didn't manage to generate an expression this time; move on.
}
}

if (generatedExprs.isEmpty()) {
// Nothing worked! Give up.
throw new FuzzedIntoACornerException();
}

// 'args' will have the final list of expressions for the array constructor. We populate
// it by repeatedly removing elements from the sequence of expressions we generated, adding
// clones of them to 'args', and then using them again and again until 'args' is full.
// 'current' and 'next' support this re-use; we move expressions from 'current' to 'next'
// until current is empty, and then swap 'current' with 'next'.
final List<Expr> args = new ArrayList<>();
List<Expr> current = generatedExprs;
List<Expr> next = new ArrayList<>();
for (int i = 0; i < arrayType.getArrayInfo().getConstantSize(); i++) {
assert (!current.isEmpty());
final Expr expr = current.remove(generator.nextInt(current.size()));
args.add(expr.clone());
next.add(expr);
if (current.isEmpty()) {
List<Expr> temp = current;
current = next;
next = temp;
}
}
return new ArrayConstructorExpr((ArrayType) stripQualifiers(targetType), args);
} else {
throw new FuzzedIntoACornerException();
}
}

private boolean isTooDeep(int depth) {
return isTooDeep(depth, generationParams, generator);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ protected void visitVariableDeclInfoAfterAddedToScope(VariableDeclInfo declInfo)
return;
}
ScopeEntry se = getCurrentScope().lookupScopeEntry(declInfo.getName());
if (se.getType() instanceof ArrayType) {
globalArrays.put(declInfo.getName(), ((ArrayType) se.getType()).getBaseType()
.getWithoutQualifiers());
if (se.getType().getWithoutQualifiers() instanceof ArrayType) {
globalArrays.put(declInfo.getName(), ((ArrayType) se.getType().getWithoutQualifiers())
.getBaseType());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import com.graphicsfuzz.common.ast.expr.VariableIdentifierExpr;
import com.graphicsfuzz.common.ast.stmt.NullStmt;
import com.graphicsfuzz.common.ast.stmt.Stmt;
import com.graphicsfuzz.common.ast.type.ArrayType;
import com.graphicsfuzz.common.ast.type.BasicType;
import com.graphicsfuzz.common.ast.type.LayoutQualifierSequence;
import com.graphicsfuzz.common.ast.type.QualifiedType;
Expand Down Expand Up @@ -741,12 +740,6 @@ private boolean compatibleDonor(TranslationUnit donor,
}

Type dropQualifiersThatCannotBeUsedForLocalVariable(Type type) {
if (type instanceof ArrayType) {
return new ArrayType(
dropQualifiersThatCannotBeUsedForLocalVariable(((ArrayType) type).getBaseType()),
((ArrayType) type).getArrayInfo());
}

if (!(type instanceof QualifiedType)) {
return type;
}
Expand Down Expand Up @@ -778,14 +771,4 @@ String addPrefix(String name) {
return getPrefix() + translationUnitCount + name;
}

boolean typeRefersToUniform(Type type) {
if (type.hasQualifier(TypeQualifier.UNIFORM)) {
return true;
}
if (!(type.getWithoutQualifiers() instanceof ArrayType)) {
return false;
}
return typeRefersToUniform(((ArrayType) type.getWithoutQualifiers()).getBaseType());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.graphicsfuzz.generator.transformation;

import com.graphicsfuzz.common.ast.TranslationUnit;
import com.graphicsfuzz.common.ast.decl.ArrayInfo;
import com.graphicsfuzz.common.ast.decl.FunctionDefinition;
import com.graphicsfuzz.common.ast.decl.Initializer;
import com.graphicsfuzz.common.ast.decl.VariableDeclInfo;
Expand All @@ -25,6 +26,7 @@
import com.graphicsfuzz.common.ast.stmt.DeclarationStmt;
import com.graphicsfuzz.common.ast.stmt.IfStmt;
import com.graphicsfuzz.common.ast.stmt.Stmt;
import com.graphicsfuzz.common.ast.type.ArrayType;
import com.graphicsfuzz.common.ast.type.QualifiedType;
import com.graphicsfuzz.common.ast.type.Type;
import com.graphicsfuzz.common.ast.type.TypeQualifier;
Expand Down Expand Up @@ -103,14 +105,17 @@ Stmt prepareStatementToDonate(IInjectionPoint injectionPoint, DonationContext do
injectionPoint,
donationContext,
type,
type instanceof QualifiedType && ((QualifiedType) type)
.hasQualifier(TypeQualifier.CONST),
type.hasQualifier(TypeQualifier.CONST),
generator,
shadingLanguageVersion);

final ArrayInfo arrayInfo = type.getWithoutQualifiers() instanceof ArrayType
? ((ArrayType) type.getWithoutQualifiers()).getArrayInfo().clone()
: null;

donatedStmts.add(new DeclarationStmt(
new VariablesDeclaration(dropQualifiersThatCannotBeUsedForLocalVariable(type),
new VariableDeclInfo(newName, null,
new VariableDeclInfo(newName, arrayInfo,
initializer))));
}
}
Expand Down
Loading