diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml new file mode 100644 index 000000000..405a2b306 --- /dev/null +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -0,0 +1,10 @@ +name: "Validate Gradle Wrapper" +on: [push, pull_request] + +jobs: + validation: + name: "Validation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: gradle/wrapper-validation-action@v1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..165753b4b --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,63 @@ +# The default workflow for GitHub Actions that is used for continuous +# integration. A configuration file that is used to control when, where, +# and how different CI jobs are executed. +# For more information on how to modify this file check the following link: +# https://help.github.com/en/actions/automating-your-workflow-with-github-actions + +name: CI + +on: + push: + branches: + - '*' + pull_request: + branches: + - '*' + +jobs: + windows: + if: github.event.action != 'labeled' + name: 'Windows (JDK 8)' + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 50 + - name: 'Set up JDK 8' + uses: actions/setup-java@v1 + with: + java-version: 8 + - name: 'Test' + shell: cmd + run: | + ./gradlew --no-parallel --no-daemon build javadoc + + linux: + name: 'Linux (JDK 11)' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 50 + - name: 'Set up JDK 11' + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: 'Test' + run: | + ./gradlew --no-parallel --no-daemon build javadoc + + mac: + name: 'macOS (JDK 13)' + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 50 + - name: 'Set up JDK 13' + uses: actions/setup-java@v1 + with: + java-version: 13 + - name: 'Test' + run: | + ./gradlew --no-parallel --no-daemon build javadoc diff --git a/.gitignore b/.gitignore index 65f4bd396..41cb9351f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,11 @@ .DS_Store -build/ -target/ +/.gradle +/build/ +/target/ +/out/ +/*/build/ +/*/target/ +/*/out/ *.iml *.pyc .cache/ diff --git a/afl-proxy/build.gradle.kts b/afl-proxy/build.gradle.kts new file mode 100644 index 000000000..8f339c00b --- /dev/null +++ b/afl-proxy/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + `cpp-application` +} diff --git a/afl-proxy/src/main/cpp/afl-proxy.cpp b/afl-proxy/src/main/cpp/afl-proxy.cpp new file mode 100644 index 000000000..fccf84da4 --- /dev/null +++ b/afl-proxy/src/main/cpp/afl-proxy.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2017, University of California, Berkeley + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "afl-proxy.h" + +#define PID_MAX_LIMIT (1 << 22) // Portable upper-bound for value defined in linux/threads.h + +/* +* Proxy between AFL and JQF. Communicates to +* both via pipes -- those launched by AFL and two whose names +* are given as command line args and must be created before +* launching the proxy. +* +* This proxy is general and can be used to exchange information +* from any external utility writing in the command-line pipes. +* +* author: Caroline Lemieux +* author: Rohan Padhye +*/ + +// whether to share an extra map of PERF_SIZE after the trace bits +// (this is unused when compiling with stock AFL) +int use_perf_map = 0; + +// whether to log non-fatal (exit(1) causing messages) +// set to != 0 for debugging +int log_non_fatal = 1; + +/* +* Log proxy's progress for debugging. +* to_exit: whether to exit(1) after logging +* log_file_name: name of file in which to log +* fmt... : format string parameters +*/ +void log_to_file(int to_exit, char* log_file_name, char const *fmt, ...) { + + + /* If no log file name was provided, do not log */ + if (log_file_name == NULL){ + if (to_exit) exit(1); + else return; + } + /* if it's not an exit message and we don't log + non-fatal, do not log */ + if (!to_exit & !log_non_fatal){ + return; + } + + /* Open the log file for logging if it is not yet open */ + static FILE * log_file = NULL; + if (log_file == NULL) { + log_file = fopen(log_file_name, "w"); + if (log_file == NULL) { + printf("Couldn't open log file, %s\n", log_file_name); + exit(1); + } + } + + /* print to log file */ + va_list ap; + va_start(ap, fmt); + vfprintf(log_file, fmt, ap); + va_end(ap); + + /* flush to log file since this program might terminate strangely */ + fflush(log_file); + + /* exit if the exit parameter is given */ + if (to_exit) { + fclose(log_file); + exit(1); + } + +} + +/* main proxy driver. communication channel between a running instance + of AFL and Java */ +int main(int argc, char** argv) { + + /* usage */ + if (argc < 3 || argc > 4){ + printf("usage: %s afltojavafifo javatoaflfifo [logfile]", argv[0]); + exit(1); + } + + /* collect file names from arguments */ + char * to_java_str = argv[1]; + char * from_java_str = argv[2]; + char * log_file_name = NULL; + if (argc == 4) log_file_name = argv[3]; + + /* set up buffers */ + u8 helo[4] = {'H', 'E', 'L', 'O'}; // to set up connections + uint32_t status = 0; // to receive + send status from java + u8 buf[4]; // to receive signals from AFL + u32 child_pid = PID_MAX_LIMIT + 1; // A PID that can never exist in practice + + /* Run once? Used by afl-showmap and perhaps other tools to avoid looping. */ + bool run_once = false; + + /* temp variable to store communicated bytes */ + int comm_bytes; + +#ifdef PERF_SIZE + /* decide if perf_bits have to be shared */ + if (getenv("JQF_PERF_MAP") != NULL) { + use_perf_map = 1; + } +#endif + + /* set up FIFOs to talk to Java */ + FILE * to_java_fd = fopen(to_java_str, "w"); + if (to_java_fd == NULL){ + log_to_file(1, log_file_name, "Failed to open to java fifo %s\n", to_java_str); + } + + log_to_file(0, log_file_name, "opened to java fifo %s\n", to_java_str); + + FILE * from_java_fd = fopen(from_java_str, "r"); + if (from_java_fd == NULL){ + log_to_file(1, log_file_name, "Failed to open from java fifo %s\n", from_java_str); + } + + log_to_file(0, log_file_name, "opened from java fifo %s\n", from_java_str); + + /* set up the trace bits */ + char * shm_str = getenv(SHM_ENV_VAR); + if (shm_str == NULL){ + log_to_file(1, log_file_name, + "Error getting the address of trace_bits from env var %s\n", shm_str); + } + int shm_id = atoi(shm_str); + u8* trace_bits = (u8*) shmat(shm_id, NULL, 0); + if (trace_bits == NULL){ + log_to_file(1, log_file_name, "Error shmat()ing trace_bits from id %d\n", shm_id); + } + + /* perf map is right after coverage bit map (unused with stock AFL) */ + u32* perf_bits = (u32*) &trace_bits[MAP_SIZE]; + + /* say the first hello to AFL. use write() because we + have an int file descriptor */ + if (write(FORKSRV_FD + 1, (void*) &helo, 4) < 4) { + log_to_file(0, log_file_name, "Error saying initial hello to AFL\n"); + run_once = true; + } else { + log_to_file(0, log_file_name, "Said hello to AFL (init).\n"); + } + + /* main fuzzing loop. AFL sends ready signals through + pipe with file descriptor FORKSRV_FD */ + while (run_once || read(FORKSRV_FD,(void *)&buf, 4) == 4){ + + if (!run_once) { + /* this sends "child pid" to AFL -- we use an impossible PID + * that AFL cannot kill even in the presence of timeouts. */ + if ((comm_bytes = write(FORKSRV_FD+1, &child_pid, 4)) < 4) { + log_to_file(1, log_file_name, + "Something went wrong saying hello to AFL in loop: wrote %d bytes.\n", comm_bytes); + } + log_to_file(0, log_file_name, "Said hello to AFL (in loop).\n"); + } + + /* Say hello to Java */ + if ((comm_bytes = fwrite(&helo, 1, 4, to_java_fd)) < 4) { + log_to_file(1, log_file_name, + "Something went wrong saying hello to Java: wrote %d bytes.\n", comm_bytes); + } + /* need to flush the buffer */ + fflush(to_java_fd); + + log_to_file(0, log_file_name, "Said hello to Java.\n"); + + /* Get return code from Java */ + if ((comm_bytes = fread((void *) &status, 1 , 4, from_java_fd)) < 4) { + log_to_file(1, log_file_name, + "Something went wrong getting return status from Java: read %d bytes.\n", comm_bytes); + } + + log_to_file(0, log_file_name, "Got return status from Java.\n"); + + /* Get trace bits from Java */ + if ((comm_bytes = fread( trace_bits, 1, MAP_SIZE, from_java_fd)) < MAP_SIZE) { + log_to_file(1, log_file_name, + "Something went wrong getting trace_bits from Java: read %d bytes.\n", comm_bytes); + } + + log_to_file(0, log_file_name, "Got trace bits from java.\n"); + +#ifdef PERF_SIZE + if (use_perf_map) { + /* Get perf bits from Java */ + if ((comm_bytes = fread( perf_bits, 4, PERF_SIZE, from_java_fd)) < PERF_SIZE) { + log_to_file(1, log_file_name, + "Something went wrong getting perf_bits from Java: read %d bytes.\n", comm_bytes); + } + + log_to_file(0, log_file_name, "Got perf bits from java.\n"); + } +#endif + + if (!run_once) { + /* Tell AFL we got the return */ + if((comm_bytes = write(FORKSRV_FD + 1, &status, 4)) < 4) { + log_to_file(1, log_file_name, + "Something went wrong sending return status to AFL: wrote %d bytes.\n", comm_bytes); + } + + log_to_file(0, log_file_name, "sent return status to AFL.\n"); + } else { + break; // run_once + } + } + + /* teardown. Will probably never be called */ + if (fclose(to_java_fd) != 0) { + log_to_file(1, log_file_name, + "Something went wrong closing pipe to Java.\n"); + } + if (fclose(from_java_fd) != 0) { + log_to_file(1, log_file_name, + "Something went wrong closing pipe from Java.\n"); + } + exit(status); + +} diff --git a/afl-proxy/src/main/headers/afl-proxy.h b/afl-proxy/src/main/headers/afl-proxy.h new file mode 100644 index 000000000..e57e00ac9 --- /dev/null +++ b/afl-proxy/src/main/headers/afl-proxy.h @@ -0,0 +1,26 @@ +#ifndef PROXY_H +#define PROXY_H + +/* + Collection of definitions taken + from AFL's config.h and types.h. + + These definitions are duplicated here so + that JQF would not need to depend on AFL + being locally installed with header files, et al. +*/ + +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; + +#define MAP_SIZE (1 << 16) +#define PERF_SIZE (1 << 14) + +#define SHM_ENV_VAR "__AFL_SHM_ID" +#define FORKSRV_FD 198 + +#endif // PROXY_H diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..602e81fb7 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,252 @@ +import com.github.vlsi.gradle.properties.dsl.props +import org.gradle.api.tasks.testing.logging.TestExceptionFormat + +plugins { + id("com.gradle.plugin-publish") apply false + id("org.jetbrains.gradle.plugin.idea-ext") + id("com.github.vlsi.gradle-extensions") + id("com.github.vlsi.ide") + id("com.github.vlsi.stage-vote-release") +} + +val String.v: String get() = rootProject.extra["$this.version"] as String + +val buildVersion = "jqf".v + releaseParams.snapshotSuffix + +println("Building JQF $buildVersion") + +val enableGradleMetadata by props() +val skipJavadoc by props() + +releaseParams { + tlp.set("Jqf") + organizationName.set("rohanpadhye") + componentName.set("Jqf") + prefixForProperties.set("jqf") + svnDistEnabled.set(false) + sitePreviewEnabled.set(false) + nexus { + mavenCentral() + } + voteText.set { + """ + ${it.componentName} v${it.version}-rc${it.rc} is ready for preview. + + Git SHA: ${it.gitSha} + Staging repository: ${it.nexusRepositoryUri} + """.trimIndent() + } +} + +allprojects { + group = "edu.berkeley.cs.jqf" + version = buildVersion + + val javaUsed = file("src/main/java").isDirectory || file("src/test/java").isDirectory + if (javaUsed) { + apply(plugin = "java-library") + dependencies { + val compileOnly by configurations + compileOnly("net.jcip:jcip-annotations:1.0") + compileOnly("com.github.spotbugs:spotbugs-annotations:3.1.6") + compileOnly("com.google.code.findbugs:jsr305:3.0.2") + } + } + if (javaUsed) { + dependencies { + val implementation by configurations + implementation(platform(project(":jqf-dependencies-bom"))) + } + } + + val hasTests = file("src/test/java").isDirectory + if (hasTests) { + // Add default tests dependencies + dependencies { + val testImplementation by configurations + val testRuntimeOnly by configurations + if (project.props.bool("junit4", default = true)) { + // By default the projects (e.g. 'examples') use JUnit4 test API + testImplementation("junit:junit") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine") + } + if (project.props.bool("junit5", default = false)) { + // If junit5=true property is added to gradle.properties, then junit5 tests can be used + testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation("org.junit.jupiter:junit-jupiter-params") + } + testImplementation("org.hamcrest:hamcrest") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") + // Allow tests to print slf4j logging via log4j + testRuntimeOnly("org.slf4j:slf4j-log4j12") + } + } + + tasks.withType().configureEach { + // Ensure builds are reproducible + isPreserveFileTimestamps = false + isReproducibleFileOrder = true + dirMode = "775".toInt(8) + fileMode = "664".toInt(8) + } + + plugins.withType { + configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + withSourcesJar() + if (!skipJavadoc) { + withJavadocJar() + } + } + + repositories { + mavenCentral() + } + + apply(plugin = "maven-publish") + + if (!enableGradleMetadata) { + tasks.withType { + enabled = false + } + } + + tasks { + withType().configureEach { + options.encoding = "UTF-8" + } + + withType().configureEach { + manifest { + attributes["Bundle-License"] = "BSD-2-Clause" + attributes["Implementation-Title"] = "Jqf" + attributes["Implementation-Version"] = project.version + attributes["Specification-Vendor"] = "Jqf" + attributes["Specification-Version"] = project.version + attributes["Specification-Title"] = "Jqf" + attributes["Implementation-Vendor"] = "Jqf" + attributes["Implementation-Vendor-Id"] = "edu.berkeley.cs.jqf" + } + } + withType().configureEach { + useJUnitPlatform() + testLogging { + exceptionFormat = TestExceptionFormat.FULL + showStandardStreams = true + } + // Pass the property to tests + fun passProperty(name: String, default: String? = null) { + val value = System.getProperty(name) ?: default + value?.let { systemProperty(name, it) } + } + passProperty("junit.jupiter.execution.parallel.enabled", "true") + passProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") + passProperty("junit.jupiter.execution.timeout.default", "5 m") + } + configure { + if (project.path == ":") { + // Do not publish "root" project. Java plugin is applied here for DSL purposes only + return@configure + } + publications { + if (project.path != ":jqf-plugin-gradle") { + create(project.name) { + artifactId = project.name + version = rootProject.version.toString() + description = project.description + from(project.components.get("java")) + } + } + withType { + // if (!skipJavadoc) { + // Eager task creation is required due to + // https://github.com/gradle/gradle/issues/6246 + // artifact(sourcesJar.get()) + // artifact(javadocJar.get()) + // } + + // Use the resolved versions in pom.xml + // Gradle might have different resolution rules, so we set the versions + // that were used in Gradle build/test. + versionMapping { + usage(Usage.JAVA_RUNTIME) { + fromResolutionResult() + } + usage(Usage.JAVA_API) { + fromResolutionOf("runtimeClasspath") + } + } + pom { + withXml { + val sb = asString() + var s = sb.toString() + // compile is Maven default, so delete it + s = s.replace("compile", "") + // Cut because all dependencies have the resolved versions + s = s.replace( + Regex( + ".*?", + RegexOption.DOT_MATCHES_ALL + ), + "" + ) + sb.setLength(0) + sb.append(s) + // Re-format the XML + asNode() + } + name.set( + (project.findProperty("artifact.name") as? String) + ?: "Jqf ${project.name.capitalize()}" + ) + description.set( + project.description + ?: "Jqf ${project.name.capitalize()}" + ) + developers { + developer { + name.set("Rohan Padhye") + email.set("rohanpadhye@cs.berkeley.edu") + organization.set("University of California, Berkeley") + url.set("https://people.eecs.berkeley.edu/~rohanpadhye") + } + developer { + name.set("Caroline Lemieux") + email.set("clemieux@cs.berkeley.edu") + organization.set("University of California, Berkeley") + url.set("http://www.carolemieux.com") + } + developer { + name.set("Yevgeny Pats") + email.set("yp@fuzzit.dev") + url.set("https://fuzzit.dev") + } + } + inceptionYear.set("2018") + url.set("https://github.com/rohanpadhye/jqf") + licenses { + license { + name.set("BSD-2-Clause") + url.set("https://raw.githubusercontent.com/rohanpadhye/jqf/master/LICENSE") + comments.set("BSD-2-Clause, Copyright (c) 2017-2018 The Regents of the University of California") + distribution.set("repo") + } + } + issueManagement { + system.set("GitHub") + url.set("https://github.com/rohanpadhye/jqf/issues") + } + scm { + connection.set("scm:git:https://github.com/rohanpadhye/jqf.git") + developerConnection.set("scm:git:https://github.com/rohanpadhye/jqf.git") + url.set("https://github.com/rohanpadhye/jqf") + tag.set("HEAD") + } + } + } + } + } + } + } +} diff --git a/dependencies-bom/build.gradle.kts b/dependencies-bom/build.gradle.kts new file mode 100644 index 000000000..0c8f497c4 --- /dev/null +++ b/dependencies-bom/build.gradle.kts @@ -0,0 +1,74 @@ +plugins { + `java-platform` +} + +val String.v: String get() = rootProject.extra["$this.version"] as String + +// Note: Gradle allows to declare dependency on "bom" as "api", +// and it makes the contraints to be transitively visible +// However Maven can't express that, so the approach is to use Gradle resolution +// and generate pom files with resolved versions +// See https://github.com/gradle/gradle/issues/9866 + +fun DependencyConstraintHandlerScope.apiv( + notation: String, + versionProp: String = notation.substringAfterLast(':') +) = + "api"(notation + ":" + versionProp.v) + +fun DependencyConstraintHandlerScope.runtimev( + notation: String, + versionProp: String = notation.substringAfterLast(':') +) = + "runtime"(notation + ":" + versionProp.v) + +dependencies { + // Parenthesis are needed here: https://github.com/gradle/gradle/issues/9248 + (constraints) { + // api means "the dependency is for both compilation and runtime" + // runtime means "the dependency is only for runtime, not for compilation" + // In other words, marking dependency as "runtime" would avoid accidental + // dependency on it during compilation + apiv("com.google.errorprone:error_prone_check_api", "error_prone") + apiv("com.google.errorprone:error_prone_core", "error_prone") + apiv("com.google.errorprone:error_prone_test_helpers", "error_prone") + apiv("com.google.guava:guava") + apiv("com.google.guava:guava-testlib", "guava") + apiv("com.google.javascript:closure-compiler") + apiv("com.pholser:junit-quickcheck-core", "junit-quickcheck") + apiv("com.pholser:junit-quickcheck-generators", "junit-quickcheck") + apiv("com.pholser:junit-quickcheck-generators", "junit-quickcheck") + apiv("info.picocli:picocli") + apiv("junit:junit", "junit4") + apiv("org.apache.ant:ant") + apiv("org.apache.bcel:bcel") + apiv("org.apache.commons:commons-collections4") + apiv("org.apache.commons:commons-compress") + apiv("org.apache.commons:commons-lang3") + apiv("org.apache.commons:commons-math3") + apiv("org.apache.maven:maven-model-builder") + apiv("org.apache.struts:struts2-core") + apiv("org.apache.tika:tika-parsers") + apiv("org.apache.tomcat:tomcat-catalina") + apiv("org.apache.tomcat:tomcat-coyote") + apiv("org.exparity:hamcrest-date") + apiv("org.hamcrest:hamcrest") + apiv("org.hamcrest:hamcrest-core", "hamcrest") + apiv("org.hamcrest:hamcrest-library", "hamcrest") + apiv("org.jacoco:org.jacoco.report", "jacoco") + apiv("org.jgrapht:jgrapht-core", "jgrapht") + apiv("org.jgrapht:jgrapht-ext", "jgrapht") + apiv("org.junit.jupiter:junit-jupiter-api", "junit5") + apiv("org.junit.jupiter:junit-jupiter-params", "junit5") + apiv("org.lichess:scalachess_2.12") + apiv("org.mockito:mockito-core") + apiv("org.mozilla:rhino") + apiv("org.ow2.asm:asm", "asm") + apiv("org.slf4j:slf4j-api", "slf4j") + apiv("org.slf4j:slf4j-log4j12", "slf4j") + + + runtimev("org.junit.jupiter:junit-jupiter-engine", "junit5") + runtimev("org.junit.vintage:junit-vintage-engine", "junit5") + } +} diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts new file mode 100644 index 000000000..dde9fc1cc --- /dev/null +++ b/examples/build.gradle.kts @@ -0,0 +1,44 @@ +dependencies { + api(project(":jqf-fuzz")) + api("com.pholser:junit-quickcheck-core") + api("com.pholser:junit-quickcheck-generators") + api("org.jgrapht:jgrapht-core") + api("com.google.guava:guava") + api("org.lichess:scalachess_2.12") + api("org.apache.bcel:bcel") + + testImplementation(project(":jqf-instrument")) + + testImplementation("org.jgrapht:jgrapht-ext") + testImplementation("org.apache.commons:commons-compress") + testImplementation("org.apache.commons:commons-collections4") + testImplementation("org.apache.commons:commons-lang3") + testImplementation("org.apache.commons:commons-math3") + testImplementation("org.apache.struts:struts2-core") + testImplementation("org.apache.tomcat:tomcat-coyote") + testImplementation("org.apache.tomcat:tomcat-catalina") + testImplementation("org.apache.maven:maven-model-builder") + testImplementation("com.google.javascript:closure-compiler") + testImplementation("org.mozilla:rhino") + testImplementation("org.apache.ant:ant") + testImplementation("com.google.errorprone:error_prone_check_api") + testImplementation("com.google.errorprone:error_prone_test_helpers") { + // It uses 4.13-SNAPSHOT + exclude("junit", "junit") + } + testImplementation("com.google.errorprone:error_prone_core") + testImplementation("com.google.guava:guava-testlib") + testImplementation("org.apache.tika:tika-parsers") +} + +repositories { + maven { + url = uri("https://raw.githubusercontent.com/ornicar/lila-maven/master") + } +} + +tasks { + test { + enabled = false + } +} diff --git a/fuzz/build.gradle.kts b/fuzz/build.gradle.kts new file mode 100644 index 000000000..cf163bd89 --- /dev/null +++ b/fuzz/build.gradle.kts @@ -0,0 +1,38 @@ +plugins { + id("com.github.johnrengelman.shadow") +} + +val zestCli by configurations.creating { + extendsFrom(configurations.runtimeClasspath.get()) +} + +dependencies { + api(project(":jqf-instrument")) + api("com.pholser:junit-quickcheck-core") + api("com.pholser:junit-quickcheck-generators") + api("info.picocli:picocli") + + implementation("org.jacoco:org.jacoco.report") + + testImplementation("org.mockito:mockito-core") + + // Add logging to zest-cli.jar otherwise slf4j won't print the logging + zestCli("org.slf4j:slf4j-log4j12") +} + +tasks { + jar { + dependsOn(shadowJar) + } + + shadowJar { + manifest { + attributes["Main-Class"] = "edu.berkeley.cs.jqf.fuzz.ei.ZestCLI" + } + archiveClassifier.set("zest-cli") + configurations = listOf(zestCli) + exclude("META-INF/maven/**") + exclude("META-INF/LICENSE*") + exclude("META-INF/NOTICE*") + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..7ea52967e --- /dev/null +++ b/gradle.properties @@ -0,0 +1,49 @@ +# Gradle +org.gradle.parallel=true +kotlin.code.style=official + +# See https://github.com/gradle/gradle/pull/11358 , https://issues.apache.org/jira/browse/INFRA-14923 +# repository.apache.org does not yet support .sha256 and .sha512 checksums +systemProp.org.gradle.internal.publish.checksums.insecure=true + +# Autostyle +jqf.version=1.4 + +# Plugins +com.github.ben-manes.versions.version=0.22.0 +com.github.vlsi.vlsi-release-plugins.version=1.53 +com.gradle.plugin-publish.version=0.10.1 +com.jfrog.bintray.version=1.8.4 +org.jdrupes.mdoclet.version=1.0.5 +org.jetbrains.gradle.plugin.idea-ext.version=0.7 +com.github.johnrengelman.shadow.version=5.1.0 + +# Dependencies +asm.version=7.2 +picocli.version=4.0.4 +jacoco.version=0.8.2 +hamcrest-date.version=2.0.4 +hamcrest.version=2.1 +junit-quickcheck.version=0.9 +junit4.version=4.12 +junit5.version=5.6.0-M1 +mockito-core.version=2.33.4 +slf4j.version=1.7.25 + +jgrapht.version=1.0.1 +guava.version=24.1-jre +scalachess_2.12.version=8.6.8 +bcel.version=6.2 +rhino.version=1.7.8 +commons-compress.version=1.18 +commons-collections4.version=4.3 +commons-lang3.version=3.7 +commons-math3.version=3.6.1 +struts2-core.version=2.5.13 +tomcat-coyote.version=9.0.1 +tomcat-catalina.version=9.0.1 +maven-model-builder.version=3.5.2 +closure-compiler.version=v20180204 +ant.version=1.10.2 +error_prone.version=2.2.0 +tika-parsers.version=1.18 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..5c2d1cf01 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..2446803db --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionSha256Sum=634f972af958e3c753aeb42d7a688fab6820b527a0aef9eed03d7f3f6f9c7c06 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..83f2acfdc --- /dev/null +++ b/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..9618d8d96 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/instrument/build.gradle.kts b/instrument/build.gradle.kts new file mode 100644 index 000000000..c2ec78583 --- /dev/null +++ b/instrument/build.gradle.kts @@ -0,0 +1,11 @@ +dependencies { + implementation("org.ow2.asm:asm") +} + +tasks.jar { + manifest { + attributes["Premain-Class"] = "janala.instrument.SnoopInstructionTransformer" + attributes["Can-Redefine-Classes"] = true + attributes["Can-Retransform-Classes"] = true + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 000000000..2d815e214 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,34 @@ +pluginManagement { + plugins { + fun String.v() = extra["$this.version"].toString() + fun PluginDependenciesSpec.idv(id: String, key: String = id) = id(id) version key.v() + + idv("com.github.johnrengelman.shadow") + idv("com.github.vlsi.crlf", "com.github.vlsi.vlsi-release-plugins") + idv("com.github.vlsi.gradle-extensions", "com.github.vlsi.vlsi-release-plugins") + idv("com.github.vlsi.ide", "com.github.vlsi.vlsi-release-plugins") + idv("com.github.vlsi.license-gather", "com.github.vlsi.vlsi-release-plugins") + idv("com.github.vlsi.stage-vote-release", "com.github.vlsi.vlsi-release-plugins") + idv("com.gradle.plugin-publish") + idv("org.jetbrains.gradle.plugin.idea-ext") + } +} + +rootProject.name = "jqf" + +include( + "afl-proxy" +) + +for (p in listOf( + "dependencies-bom", + "fuzz", + "instrument", + "examples", + "maven-plugin" +)) { + include(p) + project(":$p").apply { + name = "jqf-$p" + } +}