Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5c3e88c
switching to develop
lehvolk May 22, 2023
0ce1a3c
make AbstractFullExprSetCollector api be Java friendly
lehvolk May 24, 2023
9631fef
working on caching settings
lehvolk May 24, 2023
4047569
cleanup
lehvolk May 24, 2023
0a089d4
[jacodb-ifds] Fix usage of locals criteria
volivan239 May 22, 2023
d414110
[jacodb-ifds] Add JodaTime tests
volivan239 May 24, 2023
fa8384b
Fix cfg build of virtual calls
volivan239 May 24, 2023
801c1d2
Disabled long-running test
volivan239 May 24, 2023
9c021f3
Fix swapped rhv and lhv in JcRawConditionExprs (#82)
volivan239 May 24, 2023
7178361
[jacodb-ifds] Filter inappropriate candidates in virtual calls devirt…
volivan239 May 24, 2023
91d8f0a
build snapshots from develop branch
lehvolk May 25, 2023
a5f87c8
bring methodRef separation (special, static etc) back
lehvolk May 25, 2023
57a56c1
- review features api
lehvolk May 25, 2023
32ce228
fix tests
lehvolk May 25, 2023
11c889e
tests for caching
lehvolk May 25, 2023
f8be865
fix tests
lehvolk May 25, 2023
d740896
- fix tests
lehvolk May 25, 2023
78e7049
fix too many puts in cache
lehvolk May 26, 2023
5929195
fix missed cfg/instructions caching
lehvolk May 26, 2023
2b84a86
[jacodb-ifds] Improve cli api + test for cli
volivan239 May 25, 2023
24339b0
better equality of JcClassTypes
lehvolk May 26, 2023
fa6f811
Add ability to override real method closes #85
lehvolk May 26, 2023
cca1117
Typo in the JcRawDynamicCallExpr/JcDynamicCallExpr member names and J…
lehvolk May 26, 2023
debf15b
add coverage infrastructure
lehvolk May 29, 2023
d46e4db
fix coverage build
lehvolk May 29, 2023
303e4b1
makes builds faster by adding indexes for cascading deletes of byteco…
lehvolk May 29, 2023
08d0cf4
fix tests
lehvolk May 29, 2023
fbd93dd
get rid of custom serializer
lehvolk May 29, 2023
59f1c40
fix coverage report action
lehvolk May 29, 2023
4dfb582
fix coverage report action
lehvolk May 29, 2023
0dcd436
Autogenerated JaCoCo coverage badges
github-actions[bot] May 29, 2023
741944c
add coverage badge
lehvolk May 29, 2023
ef42c85
Autogenerated JaCoCo coverage badges
github-actions[bot] May 29, 2023
8e19579
fix coverage badge
lehvolk May 29, 2023
d7f9df2
Autogenerated JaCoCo coverage badges
github-actions[bot] May 29, 2023
e9e0e7c
Merge branch 'main' of https://github.com/UnitTestBot/jacodb into dev…
lehvolk May 29, 2023
995c6ac
Merge branch 'main' into develop
lehvolk May 30, 2023
6afa465
splitting `analysis` module into two: `analysis` and `cli`
lehvolk May 30, 2023
3b6b196
Autogenerated JaCoCo coverage badges
github-actions[bot] May 30, 2023
787406f
add publication of release artifacts
lehvolk May 30, 2023
3bf4e1e
fix dokka memory consumption
lehvolk May 30, 2023
cedfbe1
fix dokka memory consumption
lehvolk May 30, 2023
49a6c1a
Autogenerated JaCoCo coverage badges
github-actions[bot] May 30, 2023
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
13 changes: 12 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,20 @@ jobs:
gradle-version: 7.6.1
arguments: |
publish
-PincludeDokka=true
-PsemVer=${{inputs.semVer}}
-Pactor=${{ secrets.MAVEN_CENTRAL_LOGIN }}
-Ptoken=${{ secrets.MAVEN_CENTRAL_TOKEN }}
-PgpgKey="${{ secrets.OSSRH_GPG_SECRET_KEY }}"
-PgpgPassphrase=${{ secrets.OSSRH_GPG_SECRET_PASSPHRASE }}
-PrepoUrl=https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
-PrepoUrl=https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
- name: Upload release artifacts
uses: softprops/action-gh-release@v1
with:
draft: true
files: |
jacodb-api/build/libs/jacodb-api-${{inputs.semVer}}.jar
jacodb-analysis/build/libs/jacodb-analysis-${{inputs.semVer}}.jar
jacodb-core/build/libs/jacodb-core-${{inputs.semVer}}.jar
jacodb-cli/build/libs/jacodb-cli-${{inputs.semVer}}.jar
jacodb-examples/build/libs/jacodb-examples-${{inputs.semVer}}.jar
8 changes: 6 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ val kotlinVersion: String by rootProject
val coroutinesVersion: String by rootProject
val junit5Version: String by project
val semVer: String? by project
val includeDokka: String? by project

group = "org.jacodb"

Expand Down Expand Up @@ -125,14 +126,17 @@ allprojects {
archiveClassifier.set("javadoc")
}


val sourcesJar by creating(Jar::class) {
archiveClassifier.set("sources")
from(sourceSets.getByName("main").kotlin.srcDirs)
}

artifacts {
archives(sourcesJar)
archives(dokkaJavadocJar)
if (includeDokka != null) {
archives(dokkaJavadocJar)
}
}
}

Expand Down Expand Up @@ -170,7 +174,7 @@ if (!repoUrl.isNullOrEmpty()) {
listOf(
project(":jacodb-api"),
project(":jacodb-core"),
// project(":jacodb-analysis"),
project(":jacodb-analysis"),
)
) {
publishing {
Expand Down
2 changes: 1 addition & 1 deletion docs/badges/branches.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/badges/coverage-summary.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"branches": 68.34195614683419, "coverage": 70.38198957259596}
{"branches": 68.14246846401187, "coverage": 69.80196523053665}
2 changes: 1 addition & 1 deletion docs/badges/jacoco.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 7 additions & 8 deletions jacodb-analysis/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@ dependencies {
api(project(":jacodb-api"))

testImplementation(testFixtures(project(":jacodb-core")))
testFixturesImplementation(project(":jacodb-api"))
testFixturesImplementation("javax.servlet:servlet-api:2.5")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.2")
testImplementation(files("src/testFixtures/resources/juliet.jar"))
testImplementation(files("src/testFixtures/resources/pointerbench.jar"))
testImplementation("joda-time:joda-time:2.12.5")
testImplementation(project(":jacodb-api"))
testImplementation(group = "javax.servlet", name = "servlet-api", version = "2.5")
testImplementation(group = "org.junit.jupiter", name = "junit-jupiter-params", version = "5.9.2")
testImplementation(files("src/test/resources/juliet.jar"))
testImplementation(files("src/test/resources/pointerbench.jar"))
testImplementation(group = "joda-time", name = "joda-time", version = "2.12.5")

implementation("org.jetbrains.kotlinx:kotlinx-cli:0.3.5")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1")
implementation(group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version = "1.4.1")
implementation(group = "io.github.microutils", name = "kotlin-logging", version = "1.8.3")
}
178 changes: 15 additions & 163 deletions jacodb-analysis/src/main/kotlin/org/jacodb/analysis/AnalysisMain.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,8 @@
*/

package org.jacodb.analysis
import kotlinx.cli.ArgParser
import kotlinx.cli.ArgType
import kotlinx.cli.default
import kotlinx.cli.required
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.encodeToStream
import mu.KLogging
import org.jacodb.analysis.analyzers.AliasAnalyzer
import org.jacodb.analysis.analyzers.NpeAnalyzer
import org.jacodb.analysis.analyzers.TaintAnalysisNode
Expand All @@ -41,12 +33,7 @@ import org.jacodb.api.JcClasspath
import org.jacodb.api.JcMethod
import org.jacodb.api.analysis.JcApplicationGraph
import org.jacodb.api.cfg.JcInst
import org.jacodb.api.ext.findClass
import org.jacodb.impl.features.InMemoryHierarchy
import org.jacodb.impl.features.Usages
import org.jacodb.impl.features.usagesExt
import org.jacodb.impl.jacodb
import java.io.File
import java.util.*

@Serializable
Expand Down Expand Up @@ -95,38 +82,40 @@ class UnusedVariableAnalysisFactory : AnalysisEngineFactory {
}

override val name: String
get() = "Jacodb-Unused-Variable"
get() = "unused-variable"
}

abstract class FlowDroidFactory : AnalysisEngineFactory {

protected abstract fun getAnalyzer(graph: JcApplicationGraph): Analyzer
protected abstract val JcApplicationGraph.analyzer: Analyzer

override fun createAnalysisEngine(
graph: JcApplicationGraph,
points2Engine: Points2Engine,
): AnalysisEngine {
val analyzer = getAnalyzer(graph)
val analyzer = graph.analyzer
return TaintAnalysisWithPointsTo(graph, analyzer, points2Engine)
}

override val name: String
get() = "JacoDB-FlowDroid"
get() = "flow-droid"
}

class NPEAnalysisFactory : FlowDroidFactory() {
override fun getAnalyzer(graph: JcApplicationGraph): Analyzer {
return NpeAnalyzer(graph)
}
override val JcApplicationGraph.analyzer: Analyzer
get() {
return NpeAnalyzer(this)
}
}

class AliasAnalysisFactory(
private val generates: (JcInst) -> List<TaintAnalysisNode>,
private val isSink: (JcInst, DomainFact) -> Boolean,
) : FlowDroidFactory() {
override fun getAnalyzer(graph: JcApplicationGraph): Analyzer {
return AliasAnalyzer(graph, generates, isSink)
}
override val JcApplicationGraph.analyzer: Analyzer
get() {
return AliasAnalyzer(this, generates, isSink)
}
}

interface Points2EngineFactory : Factory {
Expand All @@ -140,7 +129,7 @@ interface GraphFactory : Factory {
class JcSimplifiedGraphFactory(
private val bannedPackagePrefixes: List<String>? = null
) : GraphFactory {
override val name: String = "JacoDB-graph simplified for IFDS"
override val name: String = "ifds-simplification"

override fun createGraph(
classpath: JcClasspath
Expand All @@ -154,7 +143,7 @@ class JcSimplifiedGraphFactory(
}
}

class JcNaivePoints2EngineFactory : Points2EngineFactory {
object JcNaivePoints2EngineFactory : Points2EngineFactory {
override fun createPoints2Engine(
graph: JcApplicationGraph,
): Points2Engine {
Expand All @@ -163,147 +152,10 @@ class JcNaivePoints2EngineFactory : Points2EngineFactory {
}

override val name: String
get() = "JacoDB-P2-Naive"
get() = "naive-p2"
}

inline fun <reified T : Factory> loadFactories(): List<T> {
assert(T::class.java != Factory::class.java)
return ServiceLoader.load(T::class.java).toList()
}

private inline fun <reified T : Factory> factoryChoice(): ArgType.Choice<T> {
val factories = loadFactories<T>()
val nameToFactory = { requiredFactoryName: String -> factories.single { it.name == requiredFactoryName } }
val factoryToName = { factory: T -> factory.name }

return ArgType.Choice(factories, nameToFactory, factoryToName)
}

private val logger = object : KLogging() {}.logger


class AnalysisMain {
fun run(args: List<String>) = main(args.toTypedArray())
}

fun loadAnalysisEngineFactoriesByConfig(config: AnalysisConfig): List<AnalysisEngineFactory> {
return config.analyses.mapNotNull { (analysis, _) ->
when (analysis) {
"NPE" -> NPEAnalysisFactory()
"Unused" -> UnusedVariableAnalysisFactory()
else -> {
logger.error { "Unknown analysis type: $analysis" }
null
}
}
}
}

fun main(args: Array<String>) {
val parser = ArgParser("taint-analysis")
val configFilePath by parser.option(
ArgType.String,
fullName = "analysisConf",
shortName = "a",
description = "File with analysis configuration in JSON format"
).required()
val cacheDirPath by parser.option(
ArgType.String,
fullName = "cachedir",
shortName = "c",
description = "Directory with caches for analysis. All parent directories will be created if not exists. Directory will be created if not exists. Directory must be empty."
).required()
val startClasses by parser.option(
ArgType.String,
fullName = "start",
shortName = "s",
description = "classes from which to start the analysis"
).required()
val outputPath by parser.option(
ArgType.String,
fullName = "output",
shortName = "o",
description = "File where analysis report will be written. All parent directories will be created if not exists. File will be created if not exists. Existing file will be overwritten."
).default("report.txt") // TODO: create SARIF here
val graphFactory by parser.option(
factoryChoice<GraphFactory>(),
fullName = "graph-type",
shortName = "g",
description = "Type of code graph to be used by analysis."
).default(JcSimplifiedGraphFactory())
val points2Factory by parser.option(
factoryChoice<Points2EngineFactory>(),
fullName = "points2",
shortName = "p2",
description = "Type of points-to engine."
).default(JcNaivePoints2EngineFactory())
val classpath by parser.option(
ArgType.String,
fullName = "classpath",
shortName = "cp",
description = "Classpath for analysis. Used by JacoDB."
).default(System.getProperty("java.class.path"))

parser.parse(args)

val outputFile = File(outputPath)

if (outputFile.exists() && outputFile.isDirectory) {
throw IllegalArgumentException("Provided path for output file is directory, please provide correct path")
} else if (outputFile.exists()) {
logger.info { "Output file $outputFile already exists, results will be overwritten" }
}

val cacheDir = File(cacheDirPath)

if (!cacheDir.exists()) {
cacheDir.mkdirs()
}

if (!cacheDir.isDirectory) {
throw IllegalArgumentException("Provided path to cache directory is not directory")
}

val configFile = File(configFilePath)
if (!configFile.isFile) {
throw IllegalArgumentException("Can't find provided config file $configFilePath")
}
val config = Json.decodeFromString<AnalysisConfig>(configFile.readText())

val classpathAsFiles = classpath.split(File.pathSeparatorChar).sorted().map { File(it) }
val classpathHash = classpath.hashCode()
val persistentPath = cacheDir.resolve("jacodb-for-$classpathHash")

val cp = runBlocking {
val jacodb = jacodb {
loadByteCode(classpathAsFiles)
persistent(persistentPath.absolutePath)
installFeatures(InMemoryHierarchy, Usages)
}
jacodb.classpath(classpathAsFiles)
}

val graph = graphFactory.createGraph(cp)
val points2Engine = points2Factory.createPoints2Engine(graph)
val startJcClasses = startClasses.split(";").map { cp.findClass(it) }

val analysisEngines = loadAnalysisEngineFactoriesByConfig(config).map {
it.createAnalysisEngine(graph, points2Engine)
}

val analysisResults = analysisEngines.map { engine ->
startJcClasses.forEach { clazz ->
clazz.declaredMethods.forEach {
engine.addStart(it)
}
}
engine.analyze()
}

val mergedResult = DumpableAnalysisResult(analysisResults.flatMap { it.foundVulnerabilities })

val json = Json { prettyPrint = true }
outputFile.outputStream().use { fileOutputStream ->
json.encodeToStream(mergedResult, fileOutputStream)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class AliasAnalysisTest : BaseTest() {
.plus("pointerbench.benchmark.internal")

val graph = JcSimplifiedGraphFactory(bannedPackagePrefixes).createGraph(cp)
val points2Engine = JcNaivePoints2EngineFactory().createPoints2Engine(graph)
val points2Engine = JcNaivePoints2EngineFactory.createPoints2Engine(graph)
val factory = AliasAnalysisFactory(::generates, ::isSink)
val ifds = factory.createAnalysisEngine(graph, points2Engine)
ifds.addStart(method)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class JodaDateTimeAnalysisTest : BaseTest() {
val clazz = cp.findClass<DateTime>()

val graph = JcSimplifiedGraphFactory().createGraph(cp)
val points2Engine = JcNaivePoints2EngineFactory().createPoints2Engine(graph)
val points2Engine = JcNaivePoints2EngineFactory.createPoints2Engine(graph)
val ifds = factory.createAnalysisEngine(graph, points2Engine)
clazz.declaredMethods
.forEach { ifds.addStart(it) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import org.jacodb.analysis.NPEAnalysisFactory
import org.jacodb.analysis.VulnerabilityInstance
import org.jacodb.analysis.analyzers.NpeAnalyzer
import org.jacodb.analysis.graph.JcApplicationGraphImpl
import org.jacodb.analysis.samples.NPEExamples
import org.jacodb.api.JcClassOrInterface
import org.jacodb.api.JcMethod
import org.jacodb.api.ext.constructors
Expand All @@ -37,6 +36,7 @@ import org.jacodb.impl.features.usagesExt
import org.jacodb.testing.BaseTest
import org.jacodb.testing.WithDB
import org.jacodb.testing.allClasspath
import org.jacodb.testing.analysis.NPEExamples
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
Expand Down Expand Up @@ -273,7 +273,7 @@ class NpeAnalysisTest : BaseTest() {

private fun findNpeSources(method: JcMethod): List<VulnerabilityInstance> {
val graph = JcSimplifiedGraphFactory().createGraph(cp)
val points2Engine = JcNaivePoints2EngineFactory().createPoints2Engine(graph)
val points2Engine = JcNaivePoints2EngineFactory.createPoints2Engine(graph)
val ifds = NPEAnalysisFactory().createAnalysisEngine(graph, points2Engine)
ifds.addStart(method)
val result = ifds.analyze()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class UnusedVariableTest : BaseTest() {

private fun findUnusedVariables(method: JcMethod): List<VulnerabilityInstance> {
val graph = JcSimplifiedGraphFactory().createGraph(cp)
val points2Engine = JcNaivePoints2EngineFactory().createPoints2Engine(graph)
val points2Engine = JcNaivePoints2EngineFactory.createPoints2Engine(graph)
val ifds = UnusedVariableAnalysisFactory().createAnalysisEngine(graph, points2Engine)
ifds.addStart(method)
val result = ifds.analyze()
Expand Down
Loading