JazzerTask.java

package io.micronaut.fuzzing.jazzer;

import io.micronaut.fuzzing.model.DefinedFuzzTarget;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import org.gradle.process.ExecOperations;

import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

public abstract class JazzerTask extends BaseJazzerTask {
    @InputDirectory
    @Optional
    public abstract DirectoryProperty getCorpus();

    @Input
    @Optional
    public abstract Property<Integer> getForks();

    @Input
    @Optional
    public abstract Property<Integer> getJobs();

    @InputFile
    @Nonnull
    @Optional
    public abstract RegularFileProperty getMinimizeCrashFile();

    @OutputFile
    @Nonnull
    @Optional
    public abstract RegularFileProperty getCoverageDumpFile();

    @Input
    @Optional
    public abstract Property<Integer> getRssLimitMb();

    @Input
    @Optional
    public abstract Property<Duration> getMaxTotalTime();

    @Inject
    protected abstract ExecOperations getExecOperations();

    @TaskAction
    public void run() throws IOException {
        try (ClasspathAccess classpathAccess = new ClasspathAccess()) {
            for (DefinedFuzzTarget target : findFuzzTargets(classpathAccess)) {
                Path tmpDictFile = null;
                try {
                    if (target.dictionary() != null) {
                        tmpDictFile = Files.createTempFile("jazzer-dict", ".dict");
                        try (OutputStream os = Files.newOutputStream(tmpDictFile)) {
                            buildDictionary(classpathAccess, os, target);
                        }
                    }
                    Path finalTmpDictFile = tmpDictFile;
                    getExecOperations().javaexec(spec -> {
                        List<String> args = new ArrayList<>();
                        collectArgs(args, target);
                        if (getForks().isPresent()) {
                            args.add("-fork=" + getForks().get());
                        }
                        if (getJobs().isPresent()) {
                            args.add("-jobs=" + getJobs().get());
                        }
                        spec.classpath(getClasspath());
                        args.add("--cp=" + getClasspath().getAsPath());

                        if (getCoverageDumpFile().isPresent()) {
                            args.add("--coverage_dump=" + getCoverageDumpFile().getAsFile().get().getPath());
                        }
                        if (getRssLimitMb().isPresent()) {
                            args.add("-rss_limit_mb=" + getRssLimitMb().get());
                        }
                        if (getMaxTotalTime().isPresent()) {
                            args.add("-max_total_time=" + getMaxTotalTime().get().toSeconds());
                        }
                        spec.jvmArgs(getJvmArgs().get());
                        if (finalTmpDictFile != null) {
                            args.add("-dict=" + finalTmpDictFile);
                        }
                        if (getMinimizeCrashFile().isPresent()) {
                            args.add("-minimize_crash=1");
                            args.add(getMinimizeCrashFile().getAsFile().get().getPath());
                        }
                        if (getCorpus().isPresent() && !getMinimizeCrashFile().isPresent()) {
                            args.add(getCorpus().getAsFile().get().getPath());
                        }
                        spec.setArgs(args);
                        spec.getMainClass().set("com.code_intelligence.jazzer.Jazzer");
                        getLogger().quiet("Jazzer command line: {}", String.join(" ", spec.getCommandLine()));
                    });
                } finally {
                    if (tmpDictFile != null) {
                        Files.deleteIfExists(tmpDictFile);
                    }
                }
            }
        }
    }
}