aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--agent/agent_shade_rules2
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/agent/Agent.kt2
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/instrumentor/BUILD.bazel1
-rw-r--r--agent/src/main/java/com/code_intelligence/jazzer/instrumentor/CoverageRecorder.kt45
-rw-r--r--repositories.bzl9
-rw-r--r--third_party/classgraph.BUILD10
6 files changed, 68 insertions, 1 deletions
diff --git a/agent/agent_shade_rules b/agent/agent_shade_rules
index 83da8756..3a7019b9 100644
--- a/agent/agent_shade_rules
+++ b/agent/agent_shade_rules
@@ -1 +1,3 @@
rule kotlin.** com.code_intelligence.jazzer.third_party.kotlin.@1
+rule io.** com.code_intelligence.jazzer.third_party.io.@1
+rule nonapi.** com.code_intelligence.jazzer.third_party.nonapi.@1
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/agent/Agent.kt b/agent/src/main/java/com/code_intelligence/jazzer/agent/Agent.kt
index d282c84d..8f8cec33 100644
--- a/agent/src/main/java/com/code_intelligence/jazzer/agent/Agent.kt
+++ b/agent/src/main/java/com/code_intelligence/jazzer/agent/Agent.kt
@@ -17,6 +17,7 @@
package com.code_intelligence.jazzer.agent
import com.code_intelligence.jazzer.instrumentor.ClassNameGlobber
+import com.code_intelligence.jazzer.instrumentor.CoverageRecorder
import com.code_intelligence.jazzer.instrumentor.InstrumentationType
import com.code_intelligence.jazzer.instrumentor.loadHooks
import com.code_intelligence.jazzer.runtime.ManifestUtils
@@ -79,6 +80,7 @@ fun premain(agentArgs: String?, instrumentation: Instrumentation) {
argumentMap["instrumentation_includes"] ?: emptyList(),
(argumentMap["instrumentation_excludes"] ?: emptyList()) + customHookNames
)
+ CoverageRecorder.classNameGlobber = classNameGlobber
val dependencyClassNameGlobber = ClassNameGlobber(
argumentMap["custom_hook_includes"] ?: emptyList(),
(argumentMap["custom_hook_excludes"] ?: emptyList()) + customHookNames
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/instrumentor/BUILD.bazel b/agent/src/main/java/com/code_intelligence/jazzer/instrumentor/BUILD.bazel
index d3f88b46..038540e5 100644
--- a/agent/src/main/java/com/code_intelligence/jazzer/instrumentor/BUILD.bazel
+++ b/agent/src/main/java/com/code_intelligence/jazzer/instrumentor/BUILD.bazel
@@ -15,6 +15,7 @@ kt_jvm_library(
"//agent/src/main/java/com/code_intelligence/jazzer/generated:JavaNoThrowMethods",
"//agent/src/main/java/com/code_intelligence/jazzer/runtime",
"//agent/src/main/java/com/code_intelligence/jazzer/utils",
+ "@com_github_classgraph_classgraph//:classgraph",
"@com_github_jetbrains_kotlin//:kotlin-reflect",
],
)
diff --git a/agent/src/main/java/com/code_intelligence/jazzer/instrumentor/CoverageRecorder.kt b/agent/src/main/java/com/code_intelligence/jazzer/instrumentor/CoverageRecorder.kt
index e7037dd0..2928e2a1 100644
--- a/agent/src/main/java/com/code_intelligence/jazzer/instrumentor/CoverageRecorder.kt
+++ b/agent/src/main/java/com/code_intelligence/jazzer/instrumentor/CoverageRecorder.kt
@@ -23,6 +23,7 @@ import com.code_intelligence.jazzer.third_party.jacoco.core.data.ExecutionDataWr
import com.code_intelligence.jazzer.third_party.jacoco.core.data.SessionInfo
import com.code_intelligence.jazzer.third_party.jacoco.core.data.SessionInfoStore
import com.code_intelligence.jazzer.third_party.jacoco.core.internal.data.CRC64
+import io.github.classgraph.ClassGraph
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.time.Instant
@@ -32,10 +33,11 @@ private data class InstrumentedClassInfo(
val classId: Long,
val initialEdgeId: Int,
val nextEdgeId: Int,
- val bytecode: ByteArray
+ val bytecode: ByteArray,
)
object CoverageRecorder {
+ var classNameGlobber = ClassNameGlobber(emptyList(), emptyList())
private val instrumentedClassInfo = mutableMapOf<String, InstrumentedClassInfo>()
private var startTimestamp: Instant? = null
private val additionalCoverage = mutableSetOf<Int>()
@@ -150,6 +152,7 @@ object CoverageRecorder {
fun analyzeCoverage(coveredIds: Set<Int>): CoverageBuilder? {
return try {
val coverage = CoverageBuilder()
+ analyzeAllUncoveredClasses(coverage)
val rawExecutionData = dumpJacocoCoverage(coveredIds) ?: return null
val executionDataStore = ExecutionDataStore()
val sessionInfoStore = SessionInfoStore()
@@ -174,4 +177,44 @@ object CoverageRecorder {
null
}
}
+
+ /**
+ * Traverses the entire classpath and analyzes all uncovered classes that match the include/exclude pattern.
+ * The returned [CoverageBuilder] will report coverage information for *all* classes on the classpath, not just
+ * those that were loaded while the fuzzer ran.
+ */
+ private fun analyzeAllUncoveredClasses(coverage: CoverageBuilder): CoverageBuilder {
+ val coveredClassNames = instrumentedClassInfo
+ .keys
+ .asSequence()
+ .map { it.replace('/', '.') }
+ .toSet()
+ val emptyExecutionDataStore = ExecutionDataStore()
+ ClassGraph()
+ .enableClassInfo()
+ .ignoreClassVisibility()
+ .rejectPackages(
+ // Always exclude Jazzer-internal packages (including ClassGraph itself) from coverage reports. Classes
+ // from the Java standard library are never traversed.
+ "com.code_intelligence.jazzer.*",
+ "jaz",
+ )
+ .scan().use { result ->
+ result.allClasses
+ .asSequence()
+ .filter { classInfo -> classNameGlobber.includes(classInfo.name) }
+ .filterNot { classInfo -> classInfo.name in coveredClassNames }
+ .forEach { classInfo ->
+ classInfo.resource.use { resource ->
+ EdgeCoverageInstrumentor(0).analyze(
+ emptyExecutionDataStore,
+ coverage,
+ resource.load(),
+ classInfo.name.replace('.', '/')
+ )
+ }
+ }
+ }
+ return coverage
+ }
}
diff --git a/repositories.bzl b/repositories.bzl
index 3a5bb3b7..23158a11 100644
--- a/repositories.bzl
+++ b/repositories.bzl
@@ -90,6 +90,15 @@ def jazzer_dependencies():
maybe(
http_archive,
+ build_file = "@jazzer//third_party:classgraph.BUILD",
+ name = "com_github_classgraph_classgraph",
+ sha256 = "2b7c3930f007e4acca8a50a26957b09a55b2fabd23ed00715516a114ae3f1c1e",
+ strip_prefix = "classgraph-classgraph-4.8.116",
+ url = "https://github.com/classgraph/classgraph/archive/refs/tags/classgraph-4.8.116.tar.gz",
+ )
+
+ maybe(
+ http_archive,
build_file = "@jazzer//third_party:asm.BUILD",
name = "jazzer_ow2_asm",
sha256 = "7b596cc584b241619911e99c5c96366fccd533b1a50b8720c151c2f74b5915e3",
diff --git a/third_party/classgraph.BUILD b/third_party/classgraph.BUILD
new file mode 100644
index 00000000..2d26caa6
--- /dev/null
+++ b/third_party/classgraph.BUILD
@@ -0,0 +1,10 @@
+load("@rules_java//java:defs.bzl", "java_library")
+
+java_library(
+ name = "classgraph",
+ srcs = glob([
+ "src/main/java/io/github/classgraph/**/*.java",
+ "src/main/java/nonapi/io/github/classgraph/**/*.java",
+ ]),
+ visibility = ["//visibility:public"],
+)