From 97cf2a2126372e09839fe0820cb00acc4199ea4a Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 26 Mar 2024 14:12:08 +0300 Subject: [PATCH 01/64] [ifds] feat: initial ifds refactor --- build.gradle.kts | 2 +- buildSrc/src/main/kotlin/Dependencies.kt | 2 +- jacodb-analysis/build.gradle.kts | 4 + .../org/jacodb/ifds/taint/FunctionWrapper.kt | 96 +++++++++ .../jacodb/ifds/taint/IndirectionHandler.kt | 85 ++++++++ .../org/jacodb/ifds/taint/TaintAnalyzer.kt | 132 ++++++++++++ .../org/jacodb/ifds/taint/TaintIfdsContext.kt | 84 ++++++++ .../org/jacodb/analysis/impl/IfdsNpeTest.kt | 42 +++- .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 42 +++- .../test/resources/simplelogger.properties | 4 +- jacodb-ifds/actors/build.gradle.kts | 7 + jacodb-ifds/actors/src/main/kotlin/Main.kt | 119 +++++++++++ .../org/jacodb/actors/api/AckMessage.kt | 22 ++ .../kotlin/org/jacodb/actors/api/Actor.kt | 26 +++ .../org/jacodb/actors/api/ActorContext.kt | 30 +++ .../kotlin/org/jacodb/actors/api/ActorPath.kt | 21 ++ .../kotlin/org/jacodb/actors/api/ActorRef.kt | 21 ++ .../org/jacodb/actors/api/ActorSpawner.kt | 30 +++ .../org/jacodb/actors/api/ActorStatus.kt | 22 ++ .../org/jacodb/actors/api/ActorSystem.kt | 29 +++ .../kotlin/org/jacodb/actors/api/Factory.kt | 21 ++ .../actors/api/options/ChannelFactory.kt | 37 ++++ .../jacodb/actors/api/options/SpawnOptions.kt | 51 +++++ .../org/jacodb/actors/api/signal/Signal.kt | 24 +++ .../jacodb/actors/impl/ActorContextImpl.kt | 56 +++++ .../org/jacodb/actors/impl/ActorPathImpl.kt | 35 ++++ .../org/jacodb/actors/impl/ActorRefImpl.kt | 32 +++ .../jacodb/actors/impl/ActorSpawnerImpl.kt | 73 +++++++ .../org/jacodb/actors/impl/ActorSystemImpl.kt | 77 +++++++ .../jacodb/actors/impl/InternalMessages.kt | 21 ++ .../kotlin/org/jacodb/actors/impl/Message.kt | 24 +++ .../jacodb/actors/impl/actors/WatcherActor.kt | 101 +++++++++ .../actors/impl/actors/WatcherMessages.kt | 47 +++++ .../jacodb/actors/impl/routing/Builders.kt | 53 +++++ .../actors/impl/routing/FirstReadyRouter.kt | 47 +++++ .../actors/impl/routing/MessageKeyRouter.kt | 43 ++++ .../actors/impl/routing/RandomRouter.kt | 37 ++++ .../actors/impl/routing/RoundRobinRouter.kt | 42 ++++ .../org/jacodb/actors/impl/util/Adapters.kt | 34 +++ .../jacodb/actors/impl/workers/ActorWorker.kt | 42 ++++ .../impl/workers/InternalActorWorker.kt | 60 ++++++ .../actors/impl/workers/UserActorWorker.kt | 133 ++++++++++++ jacodb-ifds/ifds/build.gradle.kts | 10 + .../org/jacodb/ifds/actors/ChunkManager.kt | 52 +++++ .../org/jacodb/ifds/actors/ProjectManager.kt | 38 ++++ .../kotlin/org/jacodb/ifds/actors/Runner.kt | 38 ++++ .../org/jacodb/ifds/actors/RunnerManager.kt | 67 ++++++ .../org/jacodb/ifds/actors/RunnerStorage.kt | 196 ++++++++++++++++++ .../kotlin/org/jacodb/ifds/domain/Analyzer.kt | 24 +++ .../jacodb/ifds/domain/ApplicationGraph.kt | 30 +++ .../kotlin/org/jacodb/ifds/domain/Chunk.kt | 19 ++ .../kotlin/org/jacodb/ifds/domain/Edge.kt | 22 ++ .../org/jacodb/ifds/domain/FlowFunction.kt | 36 ++++ .../org/jacodb/ifds/domain/FlowScope.kt | 32 +++ .../org/jacodb/ifds/domain/IfdsContext.kt | 30 +++ .../org/jacodb/ifds/domain/RunnerType.kt | 19 ++ .../kotlin/org/jacodb/ifds/domain/Vertex.kt | 22 ++ .../jacodb/ifds/messages/AnalyzerMessages.kt | 45 ++++ .../jacodb/ifds/messages/CommonMessages.kt | 19 ++ .../ifds/messages/IndirectionMessages.kt | 25 +++ .../jacodb/ifds/messages/StorageMessages.kt | 58 ++++++ settings.gradle.kts | 3 + 62 files changed, 2681 insertions(+), 14 deletions(-) create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/FunctionWrapper.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/IndirectionHandler.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzer.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintIfdsContext.kt create mode 100644 jacodb-ifds/actors/build.gradle.kts create mode 100644 jacodb-ifds/actors/src/main/kotlin/Main.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/AckMessage.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorPath.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Factory.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/ChannelFactory.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/InternalMessages.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/Message.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/util/Adapters.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt create mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt create mode 100644 jacodb-ifds/ifds/build.gradle.kts create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerManager.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ApplicationGraph.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerType.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt diff --git a/build.gradle.kts b/build.gradle.kts index 1b1169c68..4c7acff3d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -193,7 +193,7 @@ if (!repoUrl.isNullOrEmpty()) { groupId = "org.jacodb" artifactId = project.name addPom() - signPublication(this@configure) +// signPublication(this@configure) } } diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index 2c4ebcbbb..b3483f009 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -20,7 +20,7 @@ object Versions { const val jooq = "3.14.16" const val juliet = "1.3.2" const val junit = "5.9.2" - const val kotlin = "1.7.21" + const val kotlin = "1.9.0" const val kotlin_logging = "1.8.3" const val kotlinx_benchmark = "0.4.4" const val kotlinx_cli = "0.3.5" diff --git a/jacodb-analysis/build.gradle.kts b/jacodb-analysis/build.gradle.kts index b469f17db..19e3a7544 100644 --- a/jacodb-analysis/build.gradle.kts +++ b/jacodb-analysis/build.gradle.kts @@ -8,6 +8,9 @@ dependencies { api(project(":jacodb-api")) api(project(":jacodb-taint-configuration")) + implementation(project(":jacodb-ifds:actors")) + implementation(project(":jacodb-ifds:ifds")) + implementation(Libs.kotlin_logging) implementation(Libs.slf4j_simple) implementation(Libs.kotlinx_coroutines_core) @@ -23,6 +26,7 @@ dependencies { testImplementation(files("src/test/resources/pointerbench.jar")) testImplementation(Libs.joda_time) testImplementation(Libs.juliet_support) + for (cweNum in listOf(89, 476, 563, 690)) { testImplementation(Libs.juliet_cwe(cweNum)) } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/FunctionWrapper.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/FunctionWrapper.kt new file mode 100644 index 000000000..f97808960 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/FunctionWrapper.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.taint + +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.FlowFunction +import org.jacodb.ifds.domain.FlowScope +import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.SubscriptionOnStart +import org.jacodb.analysis.ifds.Analyzer +import org.jacodb.api.cfg.JcInst + + +class JcFlowFunctionsAdapter( + private val runnerType: RunnerType, + private val jcAnalyzer: Analyzer, + private val jcEventProcessor: FlowScope.(Event) -> Unit, +) : FlowFunction { + private val jcFlowFunctions = jcAnalyzer.flowFunctions + + override fun FlowScope.sequent(next: JcInst) = + jcFlowFunctions + .obtainSequentFlowFunction(edge.to.stmt, next) + .compute(edge.to.fact) + .forEach { newFact -> + val newEdge = Edge(edge.from, Vertex(next, newFact)) + processNewEdge(runnerType, newEdge) + } + + override fun FlowScope.callToReturn(returnSite: JcInst) = + jcFlowFunctions + .obtainCallToReturnSiteFlowFunction(edge.to.stmt, returnSite) + .compute(edge.to.fact) + .forEach { newFact -> + val newEdge = Edge(edge.from, Vertex(returnSite, newFact)) + processNewEdge(runnerType, newEdge) + } + + override fun FlowScope.callToStart(calleeStart: JcInst) = + jcFlowFunctions + .obtainCallToStartFlowFunction(edge.to.stmt, calleeStart) + .compute(edge.to.fact) + .forEach { newFact -> + val vertex = Vertex(calleeStart, newFact) + + val subscription = SubscriptionOnStart(runnerType, vertex, runnerType, edge) + add(subscription) + + val newEdge = Edge(vertex, vertex) + processNewEdge(runnerType, newEdge) + } + + override fun FlowScope.exitToReturnSite( + callerEdge: Edge, + returnSite: JcInst, + ) = jcFlowFunctions + .obtainExitToReturnSiteFlowFunction(callerEdge.to.stmt, returnSite, edge.to.stmt) + .compute(edge.to.fact) + .forEach { newFact -> + val newEdge = Edge(callerEdge.from, Vertex(returnSite, newFact)) + processNewEdge(runnerType, newEdge) + } + + private fun FlowScope.processNewEdge( + runnerType: RunnerType, + newEdge: Edge, + ) { + val edge = NewEdge(runnerType, newEdge, edge) + add(edge) + + val jcEvents = jcAnalyzer.handleNewEdge(newEdge.toJcEdge()) + for (event in jcEvents) { + jcEventProcessor(event) + } + + } +} + +private fun Vertex.toJcVertex() = org.jacodb.analysis.ifds.Vertex(stmt, fact) +private fun Edge.toJcEdge() = org.jacodb.analysis.ifds.Edge(from.toJcVertex(), to.toJcVertex()) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/IndirectionHandler.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/IndirectionHandler.kt new file mode 100644 index 000000000..65394297b --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/IndirectionHandler.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.taint + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.api.JcClassType +import org.jacodb.api.JcMethod +import org.jacodb.api.cfg.JcInst +import org.jacodb.api.cfg.JcVirtualCallExpr +import org.jacodb.api.ext.HierarchyExtension +import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.api.ext.isSubClassOf +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.IndirectionMessage +import org.jacodb.ifds.messages.ResolvedCall +import org.jacodb.ifds.messages.UnresolvedCall + +context(ActorContext) +class IndirectionHandler( + private val hierarchy: HierarchyExtension, + private val bannedPackagePrefixes: List, + private val parent: ActorRef, +) : Actor { + private val cache = hashMapOf>() + + override suspend fun receive(message: IndirectionMessage) { + // TODO: refactor it + @Suppress("UNCHECKED_CAST") + message as? UnresolvedCall ?: return + + val node = message.edge.to.stmt + + val callees = (node.callExpr?.let { sequenceOf(it.method.method) } ?: emptySequence()) + .filterNot { callee -> + bannedPackagePrefixes.any { callee.enclosingClass.name.startsWith(it) } + } + + val callExpr = node.callExpr as? JcVirtualCallExpr + if (callExpr == null) { + for (override in callees) { + parent.send(ResolvedCall(message.edge, override)) + } + return + } + val instanceClass = (callExpr.instance.type as? JcClassType)?.jcClass + if (instanceClass == null) { + parent.send(ResolvedCall(message.edge, callExpr.method.method)) + return + } + + val overrides = callees + .flatMap { callee -> + val allOverrides = cache.computeIfAbsent(callee) { + hierarchy.findOverrides(callee).toList() + }.filter { + it.enclosingClass isSubClassOf instanceClass || + // TODO: use only down-most override here + instanceClass isSubClassOf it.enclosingClass + }.asSequence() + // TODO: maybe filter inaccessible methods here? + allOverrides + sequenceOf(callee) + } + + for (override in overrides) { + parent.send(ResolvedCall(message.edge, override)) + } + } +} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzer.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzer.kt new file mode 100644 index 000000000..54c2f09f6 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzer.kt @@ -0,0 +1,132 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.taint + +import org.jacodb.ifds.domain.Analyzer +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.FlowFunction +import org.jacodb.ifds.domain.FlowScope +import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.messages.AnalyzerMessage +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.EdgeMessage +import org.jacodb.ifds.messages.NewSummaryEdge +import org.jacodb.ifds.messages.NotificationOnStart +import org.jacodb.ifds.messages.ResolvedCall +import org.jacodb.ifds.messages.UnresolvedCall +import org.jacodb.api.JcMethod +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst +import org.jacodb.api.ext.cfg.callExpr + +typealias TaintFlowScope = FlowScope + +class TaintAnalyzer( + private val applicationGraph: JcApplicationGraph, + private val flowFunction: FlowFunction, + private val runnerType: RunnerType, +) : Analyzer { + override fun step(message: AnalyzerMessage): Collection = buildList { + when (message) { + is EdgeMessage -> { + val scope = TaintFlowScope(message.edge, this) + scope.processEdge(message.edge) + } + + is ResolvedCall -> { + val scope = TaintFlowScope(message.edge, this) + @Suppress("UNCHECKED_CAST") + scope.processResolvedCall(message as ResolvedCall) + } + + is NotificationOnStart -> { + val scope = TaintFlowScope(message.edge, this) + scope.processNotificationOnStart(message) + } + + else -> { + error("Unexpected message: $message") + } + } + } + + private fun TaintFlowScope.processEdge(edge: Edge) { + val toStmt = edge.to.stmt + val method = applicationGraph.methodOf(toStmt) + + val callExpr = toStmt.callExpr + val isExit = toStmt in applicationGraph.exitPoints(method) + + when { + callExpr != null -> processCall(edge) + isExit -> processExit(edge) + else -> processSequent(edge) + } + } + + private fun TaintFlowScope.processCall(edge: Edge) { + val callMessage = UnresolvedCall(edge) + add(callMessage) + + val successors = applicationGraph.successors(edge.to.stmt) + + flowFunction.run { + for (successor in successors) { + callToReturn(successor) + } + } + } + + private fun TaintFlowScope.processExit(edge: Edge) { + val summaryEdge = NewSummaryEdge(runnerType, edge) + add(summaryEdge) + } + + private fun TaintFlowScope.processSequent(edge: Edge) { + val successors = applicationGraph.successors(edge.to.stmt) + + flowFunction.run { + for (successor in successors) { + sequent(successor) + } + } + } + + + private fun TaintFlowScope.processResolvedCall( + resolvedCall: ResolvedCall, + ) { + val entryPoints = applicationGraph.entryPoints(resolvedCall.method) + + flowFunction.run { + for (entryPoint in entryPoints) { + callToStart(entryPoint) + } + } + } + + + private fun TaintFlowScope.processNotificationOnStart(message: NotificationOnStart) { + val successors = applicationGraph.successors(message.data.to.stmt) + + flowFunction.run { + for (successor in successors) { + exitToReturnSite(message.data, successor) + } + } + } +} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintIfdsContext.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintIfdsContext.kt new file mode 100644 index 000000000..4878fb87f --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintIfdsContext.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.taint + +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.Factory +import org.jacodb.ifds.domain.Analyzer +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.domain.IfdsContext +import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.NewResult +import org.jacodb.analysis.taint.EdgeForOtherRunner +import org.jacodb.analysis.taint.NewSummaryEdge +import org.jacodb.analysis.taint.NewVulnerability +import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.analysis.taint.TaintEvent +import org.jacodb.api.JcClasspath +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst +import org.jacodb.impl.features.HierarchyExtensionImpl + +class TaintIfdsContext( + private val cp: JcClasspath, + private val graph: JcApplicationGraph, + private val jcAnalyzer: org.jacodb.analysis.ifds.Analyzer, + private val bannedPackagePrefixes: List, +) : IfdsContext { + data object Chunk1 : Chunk + data object Runner1 : RunnerType + + override fun chunkByMessage(message: CommonMessage): Chunk { + return Chunk1 + } + + override fun runnerTypeByMessage(message: CommonMessage): RunnerType { + return Runner1 + } + + override fun getAnalyzer(chunk: Chunk, type: RunnerType): Analyzer { + val wrapper = JcFlowFunctionsAdapter(Runner1, jcAnalyzer) { event -> + when (event) { + is EdgeForOtherRunner -> { + + } + + is NewSummaryEdge -> { + + } + + is NewVulnerability -> { + val result = NewResult(Runner1, event.vulnerability) + add(result) + } + } + } + + return TaintAnalyzer( + graph, + wrapper, + Runner1 + ) + } + + override fun indirectionHandlerFactory(parent: ActorRef) = + Factory { + IndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, parent) + } + +} diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt index cbbf4e952..8667fa1f6 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt @@ -16,11 +16,17 @@ package org.jacodb.analysis.impl +import org.jacodb.actors.impl.systemOf +import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.ObtainResults +import org.jacodb.ifds.taint.TaintIfdsContext import kotlinx.coroutines.runBlocking import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.npe.NpeManager -import org.jacodb.analysis.taint.TaintManager +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.npe.NpeAnalyzer import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.api.JcMethod import org.jacodb.api.ext.constructors @@ -36,9 +42,8 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource -import java.util.* +import java.util.StringTokenizer import java.util.stream.Stream -import kotlin.time.Duration.Companion.seconds private val logger = mu.KotlinLogging.logger {} @@ -196,10 +201,29 @@ class IfdsNpeTest : BaseAnalysisTest() { testOneMethod("nullAssignmentToCopy", emptyList()) } - private fun findSinks(method: JcMethod): List { - val unitResolver = SingletonUnitResolver - val manager = NpeManager(graph, unitResolver) - return manager.analyze(listOf(method), timeout = 30.seconds) + private fun findSinks(method: JcMethod): List = runBlocking { + val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) + val npeAnalyzer = NpeAnalyzer(graph) + val ifdsContext = TaintIfdsContext( + cp, + graph, + npeAnalyzer, + defaultBannedPackagePrefixes + ) + + val system = systemOf("ifds") { ProjectManager(ifdsContext) } + + for (fact in npeAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { + for (entryPoint in graph.entryPoints(method)) { + val vertex = Vertex(entryPoint, fact) + val message = NewEdge(TaintIfdsContext.Runner1, Edge(vertex, vertex), Edge(vertex, vertex)) + system.send(message) + } + } + + system.awaitTermination() + val results = system.ack { ObtainResults(it) } + results.map { it as TaintVulnerability } } @ParameterizedTest diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index aa88a286f..fef7f1901 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -16,20 +16,34 @@ package org.jacodb.analysis.impl +import org.jacodb.actors.impl.systemOf +import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.ObtainResults +import org.jacodb.ifds.taint.TaintIfdsContext +import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.ClassUnitResolver import org.jacodb.analysis.ifds.SingletonUnitResolver import org.jacodb.analysis.sarif.sarifReportFromVulnerabilities import org.jacodb.analysis.taint.TaintManager +import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.analysis.taint.toSarif +import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages +import org.jacodb.impl.features.usagesExt import org.jacodb.testing.WithDB import org.jacodb.testing.analysis.SqlInjectionExamples import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.RepeatedTest import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments @@ -70,6 +84,32 @@ class IfdsSqlTest : BaseAnalysisTest() { assertTrue(trace.isNotEmpty()) } + private fun findSinks(method: JcMethod): List = runBlocking { + val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) + val taintAnalyzer = org.jacodb.analysis.taint.TaintAnalyzer(graph) + val ifdsContext = TaintIfdsContext( + cp, + graph, + taintAnalyzer, + defaultBannedPackagePrefixes + ) + + val system = systemOf("ifds") { ProjectManager(ifdsContext) } + + for (fact in taintAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { + for (entryPoint in graph.entryPoints(method)) { + val vertex = Vertex(entryPoint, fact) + val message = NewEdge(TaintIfdsContext.Runner1, Edge(vertex, vertex), Edge(vertex, vertex)) + system.send(message) + } + } + + system.awaitTermination() + val results = system.ack { ObtainResults(it) } + results.map { it as TaintVulnerability } + } + + @ParameterizedTest @MethodSource("provideClassesForJuliet89") fun `test on Juliet's CWE 89`(className: String) { @@ -80,7 +120,7 @@ class IfdsSqlTest : BaseAnalysisTest() { } } - @Test + @RepeatedTest(1000) fun `test on specific Juliet instance`() { val className = "juliet.testcases.CWE89_SQL_Injection.s01.CWE89_SQL_Injection__connect_tcp_execute_01" testSingleJulietClass(className) { method -> diff --git a/jacodb-analysis/src/test/resources/simplelogger.properties b/jacodb-analysis/src/test/resources/simplelogger.properties index de8ce921f..36ae2abd2 100644 --- a/jacodb-analysis/src/test/resources/simplelogger.properties +++ b/jacodb-analysis/src/test/resources/simplelogger.properties @@ -4,12 +4,12 @@ # Default logging detail level for all instances of SimpleLogger. # Must be one of ("trace", "debug", "info", "warn", or "error"). # If not specified, defaults to "info". -org.slf4j.simpleLogger.defaultLogLevel=info +org.slf4j.simpleLogger.defaultLogLevel=error # Logging detail level for a SimpleLogger instance named "xxxxx". # Must be one of ("trace", "debug", "info", "warn", or "error"). # If not specified, the default logging detail level is used. -org.slf4j.simpleLogger.log.org.jacodb.analysis.ifds=debug +org.slf4j.simpleLogger.log.org.jacodb.analysis.ifds=error # Set to true if you want the current date and time to be included in output messages. # Default is false, and will output the number of milliseconds elapsed since startup. diff --git a/jacodb-ifds/actors/build.gradle.kts b/jacodb-ifds/actors/build.gradle.kts new file mode 100644 index 000000000..39fefca11 --- /dev/null +++ b/jacodb-ifds/actors/build.gradle.kts @@ -0,0 +1,7 @@ +dependencies { + implementation(Libs.kotlin_logging) + implementation(Libs.slf4j_simple) + implementation(Libs.kotlinx_coroutines_core) + + testImplementation("org.jetbrains.kotlin:kotlin-test") +} diff --git a/jacodb-ifds/actors/src/main/kotlin/Main.kt b/jacodb-ifds/actors/src/main/kotlin/Main.kt new file mode 100644 index 000000000..a1cecb5e2 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/Main.kt @@ -0,0 +1,119 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.options.ChannelFactory.Companion.buffered +import org.jacodb.actors.api.options.SpawnOptions +import org.jacodb.actors.impl.routing.firstReadyRouter +import org.jacodb.actors.impl.systemOf +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay +import mu.KotlinLogging.logger +import java.util.concurrent.atomic.AtomicIntegerArray +import kotlin.system.measureTimeMillis + +const val CNT = 1_000_000 +const val SLEEP = 0L +const val PRODUCERS = 10 + +class Msg(val id: Int, val x: Int) + +sealed interface ConsumerMessage { + data class Ack(val rendezvous: Channel) : ConsumerMessage + data class Msg(val id: Int, val x: Int) : ConsumerMessage +} + +private var sums = AtomicIntegerArray(PRODUCERS) + +class Consumer( + total: Int, +) : Actor { + + override suspend fun receive(message: ConsumerMessage) { + when (message) { + is ConsumerMessage.Msg -> sums.addAndGet(message.id, message.x) + is ConsumerMessage.Ack -> {} + } + } +} + +context(ActorContext) +class Producer( + private val consumer: ActorRef, + private val iterations: Int, + private val sleep: Long, + private val id: Int, +) : Actor { + + override suspend fun receive(message: Unit) { + repeat(iterations) { + consumer.send(ConsumerMessage.Msg(id, 1)) + delay(sleep) + } + } +} + + +sealed interface RootMessage { + object Start : RootMessage + data class GetArray(val rendezvous: Channel) : RootMessage +} + +context(ActorContext) +class Root : Actor { + // private val consumers = spawn("consumer") { Consumer(PRODUCERS) } + private val consumers = spawn("consumer", factory = firstReadyRouter(PRODUCERS) { + Consumer(PRODUCERS) + } + ) + + private val producers = List(PRODUCERS) { + spawn( + "producer#$it", + SpawnOptions.default().channelFactory(buffered(32768)) + ) { + Producer(consumers, iterations = CNT, sleep = SLEEP, it) + } + } + + override suspend fun receive(message: RootMessage) { + when (message) { + RootMessage.Start -> { + for (producer in producers) { + producer.send(Unit) + } + } + + is RootMessage.GetArray -> { + consumers.send(ConsumerMessage.Ack(message.rendezvous)) + } + } + } +} + +private val logger = logger("Main") + +suspend fun main() { + val system = systemOf("example", SpawnOptions.default(), ::Root) + val ms = measureTimeMillis { + system.send(RootMessage.Start) + system.awaitTermination() + logger.info { List(PRODUCERS) { sums.get(it) } } + } + logger.info { "Finished in $ms" } +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/AckMessage.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/AckMessage.kt new file mode 100644 index 000000000..697730aa4 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/AckMessage.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api + +interface AckMessage { + suspend fun get(): R + suspend fun put(result: R) +} \ No newline at end of file diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt new file mode 100644 index 000000000..6bacda1dc --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api + +import org.jacodb.actors.api.signal.Signal + +interface Actor { + val flag: Boolean get() = true + + suspend fun receive(message: M) + suspend fun receive(signal: Signal) {} +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt new file mode 100644 index 000000000..ccf5eafeb --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api + +import mu.KLogger + +interface ActorContext : ActorSpawner { + val self: ActorRef + + suspend fun ActorRef.send(message: TargetMessage) + + fun stop() + fun stopChild(name: String) + + val logger: KLogger +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorPath.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorPath.kt new file mode 100644 index 000000000..d5e52257c --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorPath.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api + +interface ActorPath { + operator fun div(name: String): ActorPath +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt new file mode 100644 index 000000000..dd70da07a --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api + +interface ActorRef { + val path: ActorPath +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt new file mode 100644 index 000000000..6b4c39a0f --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api + +import org.jacodb.actors.api.options.SpawnOptions + +interface ActorSpawner { + fun spawn( + name: String, + options: SpawnOptions = SpawnOptions.default(), + factory: Factory, + ): ActorRef + + fun child(name: String): ActorRef<*>? + fun children(): Collection> +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt new file mode 100644 index 000000000..bb8a1ac20 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api + +enum class ActorStatus { + BUSY, + IDLE +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt new file mode 100644 index 000000000..b03a42058 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api + +import kotlinx.coroutines.channels.Channel + +interface ActorSystem { + val name: String + + suspend fun send(message: Message) + + suspend fun ack(messageBuilder: (Channel) -> Message): R + + suspend fun awaitTermination() +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Factory.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Factory.kt new file mode 100644 index 000000000..4f252450f --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Factory.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api + +fun interface Factory { + fun ActorContext.create(): Actor +} \ No newline at end of file diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/ChannelFactory.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/ChannelFactory.kt new file mode 100644 index 000000000..6df25a2a1 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/ChannelFactory.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api.options + +import kotlinx.coroutines.channels.Channel + +fun interface ChannelFactory { + fun create(): Channel + + companion object { + fun unlimited() = ChannelFactory { + Channel(capacity = Channel.UNLIMITED) + } + + fun rendezvous() = ChannelFactory { + Channel(capacity = Channel.RENDEZVOUS) + } + + fun buffered(size: Int) = ChannelFactory { + Channel(capacity = size) + } + } +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt new file mode 100644 index 000000000..cefd4f24c --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api.options + +import kotlinx.coroutines.channels.Channel +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +data class SpawnOptions( + val channelFactory: ChannelFactory, + val coroutineContext: CoroutineContext, +) { + fun channelFactory(channelFactory: ChannelFactory) = copy( + channelFactory = channelFactory, + coroutineContext = coroutineContext + ) + + fun channel(channel: Channel) = copy( + channelFactory = { channel }, + coroutineContext = coroutineContext + ) + + fun coroutineContext(coroutineContext: CoroutineContext) = copy( + channelFactory = channelFactory, + coroutineContext = coroutineContext + ) + + companion object { + private val default = SpawnOptions( + ChannelFactory.unlimited(), + EmptyCoroutineContext + ) + + fun default(): SpawnOptions = + default + } +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt new file mode 100644 index 000000000..5c4a94c0e --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.api.signal + +import org.jacodb.actors.api.ActorRef + +sealed interface Signal { + data object PostStop : Signal + class Terminated(val ref: ActorRef<*>) +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt new file mode 100644 index 000000000..906408094 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl + +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.ActorSpawner +import org.jacodb.actors.api.Factory +import org.jacodb.actors.impl.workers.ActorWorker +import kotlinx.coroutines.channels.Channel +import mu.KLogger +import kotlin.coroutines.CoroutineContext + +internal class ActorContextImpl( + private val spawner: ActorSpawner, + private val worker: ActorWorker, + override val logger: KLogger, +) : ActorContext, ActorSpawner by spawner { + + override val self: ActorRef + get() = worker.self + + fun launch( + coroutineContext: CoroutineContext, + factory: Factory, + ) { + val actor = factory.run { create() } + worker.launchLoop(coroutineContext, actor) + } + + override suspend fun ActorRef.send(message: TargetMessage) { + worker.send(this as ActorRefImpl, message) + } + + override fun stop() { + TODO("Not yet implemented") + } + + override fun stopChild(name: String) { + TODO("Not yet implemented") + } +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt new file mode 100644 index 000000000..1f03ce0c8 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl + +import org.jacodb.actors.api.ActorPath + +internal data class ActorPathImpl( + private val path: List +) : ActorPath { + override fun div(name: String): ActorPath = + ActorPathImpl(path + name) + + override fun toString(): String = + path.joinToString(separator = "/", prefix = "/") + + companion object { + val emptyPath = ActorPathImpl(emptyList()) + } +} + +fun root(): ActorPath = ActorPathImpl.emptyPath diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt new file mode 100644 index 000000000..b3b98ac1e --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl + +import org.jacodb.actors.api.ActorPath +import org.jacodb.actors.api.ActorRef +import kotlinx.coroutines.channels.Channel + +internal class ActorRefImpl( + override val path: ActorPath, + private val channel: Channel, +) : ActorRef { + override fun toString(): String = "actor@$path" + + internal suspend fun send(message: M) { + channel.send(UserMessage(message)) + } +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt new file mode 100644 index 000000000..1b9d22a0e --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl + +import org.jacodb.actors.api.ActorPath +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.ActorSpawner +import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.options.SpawnOptions +import org.jacodb.actors.impl.workers.ActorWorker +import org.jacodb.actors.impl.workers.WorkerFactory +import kotlinx.coroutines.channels.Channel +import mu.KotlinLogging.logger + +internal class ActorSpawnerImpl( + private val self: ActorPath, + private val system: ActorSystemImpl<*>, + private val workerFactory: WorkerFactory, +) : ActorSpawner { + private val children = hashMapOf>() + + override fun spawn( + name: String, + options: SpawnOptions, + factory: Factory, + ): ActorRefImpl { + @Suppress("UNCHECKED_CAST") + val channel = options.channelFactory.create() as Channel + val ref = createRef(name, channel) + + val spawner = ActorSpawnerImpl(ref.path, system, workerFactory) + + @Suppress("UNCHECKED_CAST") + val worker = workerFactory(ref, channel, system) as ActorWorker + val context = ActorContextImpl(spawner, worker, logger(ref.path.toString())) + context.launch(options.coroutineContext, factory) + + return ref + } + + private fun createRef( + name: String, + channel: Channel, + ): ActorRefImpl { + if (children[name] != null) { + error("$self already has $name child") + } + val path = self / name + val ref = ActorRefImpl(path, channel) + children[name] = ref + return ref + } + + override fun child(name: String): ActorRef<*>? = + children[name] + + override fun children(): Collection> = + children.values +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt new file mode 100644 index 000000000..5ffd20f84 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl + +import org.jacodb.actors.api.ActorSystem +import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.options.SpawnOptions +import org.jacodb.actors.impl.actors.WatcherActor +import org.jacodb.actors.impl.actors.WatcherMessage +import org.jacodb.actors.impl.workers.internalActorWorkerFactory +import org.jacodb.actors.impl.workers.userActorWorkerFactory +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.channels.Channel + +internal class ActorSystemImpl( + override val name: String, + options: SpawnOptions, + factory: Factory, +) : ActorSystem { + private val path = root() / name + + private val userSpawner = ActorSpawnerImpl(path, this, userActorWorkerFactory) + private val internalSpawner = ActorSpawnerImpl(path, this, internalActorWorkerFactory) + + internal val scope = CoroutineScope(SupervisorJob()) + + internal val watcher = internalSpawner.spawn("watcher", factory = ::WatcherActor) + + private val user = userSpawner.spawn("usr", options, factory) + + override suspend fun send(message: Message) { + watcher.send(WatcherMessage.OutOfSystemSend) + user.send(message) + } + + override suspend fun ack(messageBuilder: (Channel) -> Message): R { + watcher.send(WatcherMessage.OutOfSystemSend) + val channel = Channel(Channel.RENDEZVOUS) + val ack = messageBuilder(channel) + user.send(ack) + val received = channel.receive() + return received + } + + private val channel = Channel(capacity = Channel.RENDEZVOUS) + + override suspend fun awaitTermination() { + watcher.send(WatcherMessage.AwaitTermination(channel)) + channel.receive() + watcher.send(WatcherMessage.Idle) + } +} + +fun systemOf( + name: String, + options: SpawnOptions = SpawnOptions.default(), + factory: Factory, +): ActorSystem = ActorSystemImpl( + name, + options, + factory +) \ No newline at end of file diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/InternalMessages.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/InternalMessages.kt new file mode 100644 index 000000000..d48f2b124 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/InternalMessages.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl + +internal sealed interface InternalMessage : Message + +data object Die : InternalMessage \ No newline at end of file diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/Message.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/Message.kt new file mode 100644 index 000000000..e540f55ac --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/Message.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl + +internal sealed interface Message + +internal data class UserMessage( + val message: M, +) : Message + diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt new file mode 100644 index 000000000..04be8b78f --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.actors + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.ActorStatus +import kotlinx.coroutines.channels.Channel + + +context(ActorContext) +internal class WatcherActor : Actor { + private sealed interface Status { + data object Idle : Status + data class DetectingTermination( + val rendezvousChannel: Channel, + ) : Status + } + + private data class State( + var status: Status, + var terminatedActors: Int, + var totalSent: Long, + var totalReceived: Long, + ) + + private val watchList = hashMapOf, Snapshot>() + private val state = State( + status = Status.Idle, + terminatedActors = 0, + totalSent = 0, + totalReceived = 0 + ) + + override suspend fun receive(message: WatcherMessage) { + when (message) { + WatcherMessage.Idle -> { + state.status = Status.Idle + } + + WatcherMessage.OutOfSystemSend -> { + state.totalSent++ + } + + is WatcherMessage.AwaitTermination -> { + state.status = Status.DetectingTermination(message.rendezvous) + } + + is WatcherMessage.Register -> { + state.terminatedActors++ + watchList[message.ref] = Snapshot(status = ActorStatus.IDLE, sent = 0, received = 0) + } + + is WatcherMessage.UpdateSnapshot -> { + updateSnapshot(message.ref, message.snapshot) + } + } + val status = state.status + if (status is Status.DetectingTermination) { + checkTermination(status.rendezvousChannel) + } + } + + private suspend fun checkTermination(rendezvousOnTermination: Channel) { + if (state.terminatedActors == watchList.size && state.totalSent == state.totalReceived) { + logger.info { "Actors: ${state.terminatedActors}/${watchList.size}" } + logger.info { "Messages: ${state.totalReceived}/${state.totalSent}" } + logger.info { "Computation finished..." } + rendezvousOnTermination.send(Unit) + } + } + + private fun updateSnapshot(ref: ActorRef<*>, newSnapshot: Snapshot) { + val currentSnapshot = watchList[ref] ?: error("$this can't find the current snapshot of $ref") + + if (newSnapshot.status == ActorStatus.BUSY && currentSnapshot.status == ActorStatus.IDLE) { + state.terminatedActors-- + } + if (newSnapshot.status == ActorStatus.IDLE && currentSnapshot.status == ActorStatus.BUSY) { + state.terminatedActors++ + } + state.totalSent += newSnapshot.sent - currentSnapshot.sent + state.totalReceived += newSnapshot.received - currentSnapshot.received + watchList[ref] = newSnapshot + } +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt new file mode 100644 index 000000000..377c51207 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.actors + +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.ActorStatus +import kotlinx.coroutines.channels.Channel + +internal data class Snapshot( + val status: ActorStatus, + val sent: Int, + val received: Int, +) + +internal sealed interface WatcherMessage { + + data object Idle : WatcherMessage + + data class Register( + val ref: ActorRef<*>, + ) : WatcherMessage + + data object OutOfSystemSend : WatcherMessage + + data class UpdateSnapshot( + val ref: ActorRef<*>, + val snapshot: Snapshot, + ) : WatcherMessage + + data class AwaitTermination( + val rendezvous: Channel, + ) : WatcherMessage +} \ No newline at end of file diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt new file mode 100644 index 000000000..8917f2744 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.routing + +import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.options.SpawnOptions + +fun roundRobinRouter( + size: Int = 8, + routeeSpawnOptions: SpawnOptions = SpawnOptions.default(), + routeeFactory: Factory, +) = Factory { + RoundRobinRouter(size, routeeSpawnOptions, routeeFactory) +} + +fun firstReadyRouter( + size: Int = 8, + routeeSpawnOptions: SpawnOptions = SpawnOptions.default(), + routeeFactory: Factory, +) = Factory { + FirstReadyRouter(size, routeeSpawnOptions, routeeFactory) +} + +fun randomRouter( + size: Int = 8, + routeeSpawnOptions: SpawnOptions = SpawnOptions.default(), + routeeFactory: Factory, +) = Factory { + RandomRouter(size, routeeSpawnOptions, routeeFactory) +} + +fun messageKeyRouter( + keyExtractor: (Message) -> Key, + routeeNameFactory: (Key) -> String = { it.toString() }, + routeeSpawnOptions: SpawnOptions = SpawnOptions.default(), + routeeFactory: KeyRouteeFactory +) = Factory { + MessageKeyRouter(keyExtractor, routeeNameFactory, routeeSpawnOptions, routeeFactory) +} \ No newline at end of file diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt new file mode 100644 index 000000000..1c41dc40d --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.routing + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.options.SpawnOptions +import org.jacodb.actors.impl.UserMessage + + +context(ActorContext) +internal class FirstReadyRouter( + size: Int, + routeeSpawnOptions: SpawnOptions, + routeeFactory: Factory, +) : Actor { + override val flag: Boolean + get() = false + + private val channel = routeeSpawnOptions.channelFactory.create() + + init { + val options = routeeSpawnOptions.channel(channel) + repeat(size) { + spawn("$it", options, routeeFactory) + } + } + + override suspend fun receive(message: Message) { + channel.send(UserMessage(message)) + } +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt new file mode 100644 index 000000000..50d24b92d --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.routing + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.options.SpawnOptions + +internal typealias KeyRouteeFactory = ActorContext.(Key) -> Actor + +context(ActorContext) +internal class MessageKeyRouter( + private val keyExtractor: (Message) -> Key, + private val routeeNameFactory: (Key) -> String, + private val routeeSpawnOptions: SpawnOptions, + private val routeeFactory: KeyRouteeFactory, +) : Actor { + private val routees = hashMapOf>() + + override suspend fun receive(message: Message) { + val key = keyExtractor(message) + val routee = routees.computeIfAbsent(key) { + val name = routeeNameFactory(key) + spawn(name, routeeSpawnOptions) { routeeFactory(key) } + } + routee.send(message) + } +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt new file mode 100644 index 000000000..2fb2ccdab --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.routing + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.options.SpawnOptions + +context(ActorContext) +internal class RandomRouter( + size: Int, + routeeSpawnOptions: SpawnOptions, + routeeFactory: Factory +) : Actor { + private val routees = List(size) { + spawn("$it", routeeSpawnOptions, routeeFactory) + } + + override suspend fun receive(message: Message) { + routees.random().send(message) + } +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt new file mode 100644 index 000000000..3f21d2c11 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.routing + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.options.SpawnOptions + +context(ActorContext) +internal class RoundRobinRouter( + private val size: Int, + routeeSpawnOptions: SpawnOptions, + routeeFactory: Factory +) : Actor { + private val routees = List(size) { + spawn("$it", routeeSpawnOptions, routeeFactory) + } + + private var counter = 0 + + override suspend fun receive(message: Message) { + routees[counter++].send(message) + if (counter == size) { + counter = 0 + } + } +} \ No newline at end of file diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/util/Adapters.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/util/Adapters.kt new file mode 100644 index 000000000..2342da46c --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/util/Adapters.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.util + +import org.jacodb.actors.api.ActorPath +import org.jacodb.actors.api.ActorRef + +//fun ActorRef.adaptWith(adapter: (R) -> T?): ActorRef = object : ActorRef{ +// override val path: ActorPath +// get() = this@adaptWith.path +// +// override suspend fun send(message: R) { +// val adaptedMessage = adapter(message) ?: return +// this@adaptWith.send(adaptedMessage) +// } +//} +// +//inline fun ActorRef.adaptType(): ActorRef = adaptWith { message -> +// message as? T +//} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt new file mode 100644 index 000000000..f48ff519a --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.workers + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.impl.ActorRefImpl +import org.jacodb.actors.impl.ActorSystemImpl +import org.jacodb.actors.impl.Message +import kotlinx.coroutines.channels.Channel +import kotlin.coroutines.CoroutineContext + +internal typealias WorkerFactory = (ActorRef<*>, Channel, ActorSystemImpl<*>) -> ActorWorker<*> + +internal interface ActorWorker { + val channel: Channel + val self: ActorRef + + fun launchLoop( + coroutineContext: CoroutineContext, + actor: Actor, + ) + + suspend fun send( + ref: ActorRefImpl, + message: TargetMessage, + ) +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt new file mode 100644 index 000000000..2b8eceade --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.workers + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.impl.ActorRefImpl +import org.jacodb.actors.impl.Message +import org.jacodb.actors.impl.UserMessage +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.launch +import kotlin.coroutines.CoroutineContext + + +internal class InternalActorWorker( + override val self: ActorRef, + override val channel: Channel, + private val scope: CoroutineScope, +) : ActorWorker { + override fun launchLoop( + coroutineContext: CoroutineContext, + actor: Actor, + ) { + scope.launch(coroutineContext) { + loop(actor) + } + } + + override suspend fun send(ref: ActorRefImpl, message: TargetMessage) { + ref.send(message) + } + + private suspend fun loop( + actor: Actor, + ) { + for (message in channel) { + @Suppress("UNCHECKED_CAST") + val userMessage = (message as UserMessage).message + actor.receive(userMessage) + } + } +} + +internal val internalActorWorkerFactory: WorkerFactory = + { self, channel, system -> InternalActorWorker(self, channel, system.scope) } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt new file mode 100644 index 000000000..d8d1db1f4 --- /dev/null +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt @@ -0,0 +1,133 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl.workers + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.ActorStatus +import org.jacodb.actors.api.signal.Signal +import org.jacodb.actors.impl.ActorRefImpl +import org.jacodb.actors.impl.Die +import org.jacodb.actors.impl.InternalMessage +import org.jacodb.actors.impl.Message +import org.jacodb.actors.impl.UserMessage +import org.jacodb.actors.impl.actors.Snapshot +import org.jacodb.actors.impl.actors.WatcherMessage +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.onSuccess +import kotlinx.coroutines.launch +import mu.KotlinLogging.logger +import kotlin.coroutines.CoroutineContext + + +internal class UserActorWorker( + override val self: ActorRef, + override val channel: Channel, + private val scope: CoroutineScope, + private val watcher: ActorRefImpl, +) : ActorWorker { + + private var received = 0 + private var sent = 0 + private var status = ActorStatus.IDLE + + private val handler = CoroutineExceptionHandler { _, it -> + System.err.println("$self: ${it.stackTraceToString()}") + } + + override fun launchLoop( + coroutineContext: CoroutineContext, + actor: Actor, + ) { + scope.launch(coroutineContext + handler) { + sendInternal(watcher, WatcherMessage.Register(self)) + loop(actor) + } + } + + override suspend fun send(ref: ActorRefImpl, message: TargetMessage) { + sent++ + ref.send(message) + } + + private suspend fun sendInternal(ref: ActorRefImpl, message: TargetMessage) { + ref.send(message) + } + + private suspend fun loop( + actor: Actor, + ) { + while (true) { + val receiveResult = channel.tryReceive() + receiveResult + .onSuccess { message -> + processMessage(actor, message) + } + if (receiveResult.isFailure) { + processEmptyChannel() + val result = channel.receive() + processMessage(actor, result) + } + } + } + + private suspend fun processMessage( + actor: Actor, + message: Message, + ) { + @Suppress("UNCHECKED_CAST") + when (message) { + is UserMessage<*> -> processUserMessage(actor, message.message as M) + is InternalMessage -> processInternalMessage(actor, message) + } + } + + private suspend fun processEmptyChannel() { + if (status == ActorStatus.BUSY) { + status = ActorStatus.IDLE + val snapshot = WatcherMessage.UpdateSnapshot(self, Snapshot(status, sent, received)) + watcher.send(snapshot) + } + } + + private suspend fun processUserMessage(actor: Actor, message: M) { + if (actor.flag) { + received++ + } + + if (status == ActorStatus.IDLE) { + status = ActorStatus.BUSY + watcher.send(WatcherMessage.UpdateSnapshot(self, Snapshot(status, sent, received))) + } + + actor.receive(message) + } + + private suspend fun processInternalMessage(actor: Actor, message: InternalMessage) { + when (message) { + Die -> { + channel.close() + actor.receive(Signal.PostStop) + } + } + } +} + +internal val userActorWorkerFactory: WorkerFactory = + { self, channel, system -> UserActorWorker(self, channel, system.scope, system.watcher) } diff --git a/jacodb-ifds/ifds/build.gradle.kts b/jacodb-ifds/ifds/build.gradle.kts new file mode 100644 index 000000000..8d2f7d540 --- /dev/null +++ b/jacodb-ifds/ifds/build.gradle.kts @@ -0,0 +1,10 @@ +dependencies { + implementation(Libs.kotlin_logging) + implementation(Libs.slf4j_simple) + implementation(Libs.kotlinx_coroutines_core) + + // ifds + implementation(project(":jacodb-ifds:actors")) + + testImplementation("org.jetbrains.kotlin:kotlin-test") +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt new file mode 100644 index 000000000..86356e833 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.actors + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.impl.routing.messageKeyRouter +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.domain.IfdsContext +import org.jacodb.ifds.messages.CommonMessage + +context(ActorContext) +class ChunkManager( + private val ifdsContext: IfdsContext, + private val chunk: Chunk, + private val parent: ActorRef, +) : Actor { + + private val routerFactory = messageKeyRouter( + ifdsContext::runnerTypeByMessage + ) { runnerType -> + RunnerManager(this@ActorContext.self, ifdsContext, chunk, runnerType) + } + + private val router = spawn( + "router", + factory = routerFactory + ) + + override suspend fun receive(message: CommonMessage) { + when { + chunk == ifdsContext.chunkByMessage(message) -> router.send(message) + + else -> parent.send(message) + } + } +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt new file mode 100644 index 000000000..a18b6449a --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.actors + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.impl.routing.messageKeyRouter +import org.jacodb.ifds.domain.IfdsContext +import org.jacodb.ifds.messages.CommonMessage + +context(ActorContext) +class ProjectManager( + private val ifdsContext: IfdsContext, +) : Actor { + private val routerFactory = messageKeyRouter( + keyExtractor = ifdsContext::chunkByMessage + ) { chunk -> ChunkManager(ifdsContext, chunk, this@ActorContext.self) } + + private val router = spawn("router", factory = routerFactory) + + override suspend fun receive(message: CommonMessage) { + router.send(message) + } +} \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt new file mode 100644 index 000000000..a3673cd9b --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.actors + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.ifds.domain.Analyzer +import org.jacodb.ifds.messages.AnalyzerMessage +import org.jacodb.ifds.messages.CommonMessage + +context(ActorContext>) +class Runner( + private val analyzer: Analyzer, + private val parent: ActorRef, +) : Actor> { + + override suspend fun receive(message: AnalyzerMessage) { + val newMessages = analyzer.step(message) + for (newMessage in newMessages) { + parent.send(newMessage) + } + } +} \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerManager.kt new file mode 100644 index 000000000..6dc69fea1 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerManager.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.actors + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.impl.routing.firstReadyRouter +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.domain.IfdsContext +import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.messages.AnalyzerMessage +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.IndirectionMessage +import org.jacodb.ifds.messages.StorageMessage + +context(ActorContext) +class RunnerManager( + private val parent: ActorRef, + private val ifdsContext: IfdsContext, + private val chunk: Chunk, + private val runnerType: RunnerType, +) : Actor { + private val routerFactory = firstReadyRouter(size = 8) { + Runner(ifdsContext.getAnalyzer(chunk, runnerType), this@ActorContext.self) + } + + private val router = spawn("router", factory = routerFactory) + + private val storage = spawn("storage") { + RunnerStorage(this@ActorContext.self, runnerType) + } + + private val indirectionHandler = spawn( + "indirection", + factory = ifdsContext.indirectionHandlerFactory(self) + ) + + override suspend fun receive(message: CommonMessage) { + when { + ifdsContext.chunkByMessage(message) == chunk && ifdsContext.runnerTypeByMessage(message) == runnerType -> { + @Suppress("UNCHECKED_CAST") + when (message) { + is StorageMessage -> storage.send(message) + is AnalyzerMessage<*, *> -> router.send(message as AnalyzerMessage) + is IndirectionMessage -> indirectionHandler.send(message) + } + } + + else -> parent.send(message) + } + } +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt new file mode 100644 index 000000000..ce60efa3f --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt @@ -0,0 +1,196 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.actors + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.EdgeMessage +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.NewResult +import org.jacodb.ifds.messages.NewSummaryEdge +import org.jacodb.ifds.messages.NotificationOnEnd +import org.jacodb.ifds.messages.NotificationOnStart +import org.jacodb.ifds.messages.ObtainResults +import org.jacodb.ifds.messages.StorageMessage +import org.jacodb.ifds.messages.SubscriptionOnEnd +import org.jacodb.ifds.messages.SubscriptionOnStart + +context(ActorContext) +class RunnerStorage( + private val parent: ActorRef, + private val runnerType: RunnerType, +) : Actor { + data class SubscriptionData( + val edge: Edge, + val subscriber: RunnerType, + ) + + private val endSubscribers = + HashMap, HashSet>>() + private val startSubscribers = + HashMap, HashSet>>() + + private val edges = hashSetOf>() + private val reasons = hashMapOf, HashSet>>() + + private val summaryEdges = hashSetOf>() + private val summaryEdgesByStart = hashMapOf, HashSet>>() + private val summaryEdgesByEnd = hashMapOf, HashSet>>() + + private val foundResults = hashSetOf() + + override suspend fun receive(message: StorageMessage) { + when (message) { + is NewEdge<*, *> -> { + @Suppress("UNCHECKED_CAST") + message as NewEdge + val edge = message.edge + + reasons + .computeIfAbsent(edge) { hashSetOf() } + .add(message.reason) + + if (edges.add(edge)) { + // new edge + parent.send(EdgeMessage(edge)) + + } + } + + is NewSummaryEdge<*, *> -> { + @Suppress("UNCHECKED_CAST") + message as NewSummaryEdge + + val edge = message.edge + if (summaryEdges.add(edge)) { + summaryEdgesByStart + .computeIfAbsent(edge.from) { hashSetOf() } + .add(edge) + summaryEdgesByEnd + .computeIfAbsent(edge.to) { hashSetOf() } + .add(edge) + + // subscriptions + sendStartNotifications(edge) + sendEndNotifications(edge) + } + } + + is SubscriptionOnStart<*, *> -> { + @Suppress("UNCHECKED_CAST") + message as SubscriptionOnStart + + val subscriptionData = SubscriptionData(message.data, message.subscriber) + + sendStartNotificationsOnExistingSummaryEdges(message.startVertex, subscriptionData) + + startSubscribers + .computeIfAbsent(message.startVertex) { hashSetOf() } + .add(subscriptionData) + } + + is SubscriptionOnEnd<*, *> -> { + @Suppress("UNCHECKED_CAST") + message as SubscriptionOnEnd + + val subscriptionData = SubscriptionData(message.data, message.subscriber) + + sendEndNotificationsOnExistingSummaryEdges(message.endVertex, subscriptionData) + + endSubscribers + .computeIfAbsent(message.endVertex) { hashSetOf() } + .add(subscriptionData) + } + + is NewResult -> { + foundResults.add(message.result) + } + + is ObtainResults -> { + message.channel.send(foundResults.toList()) + } + } + } + + private suspend fun sendStartNotificationsOnExistingSummaryEdges( + vertex: Vertex, + subscriptionData: SubscriptionData, + ) { + val summaries = summaryEdgesByStart.getOrDefault(vertex, emptySet()) + for (summaryEdge in summaries) { + val notification = NotificationOnStart( + subscriptionData.subscriber, + runnerType, + summaryEdge, + subscriptionData.edge + ) + parent.send(notification) + } + } + + private suspend fun sendEndNotificationsOnExistingSummaryEdges( + vertex: Vertex, + subscriptionData: SubscriptionData, + ) { + val summaries = summaryEdgesByEnd.getOrDefault(vertex, emptySet()) + for (summaryEdge in summaries) { + val notification = NotificationOnEnd( + subscriptionData.subscriber, + runnerType, + summaryEdge, + subscriptionData.edge + ) + parent.send(notification) + } + } + + + private suspend fun sendStartNotifications(edge: Edge) { + val currentEdgeStartSubscribers = startSubscribers + .getOrDefault(edge.from, emptySet()) + + for ((data, subscriber) in currentEdgeStartSubscribers) { + val notification = NotificationOnStart( + subscriber, + runnerType, + edge, + data + ) + parent.send(notification) + } + } + + private suspend fun sendEndNotifications(edge: Edge) { + val currentEdgeEndSubscribers = endSubscribers + .getOrDefault(edge.to, emptySet()) + + for ((data, subscriber) in currentEdgeEndSubscribers) { + val notification = NotificationOnEnd( + subscriber, + runnerType, + edge, + data + ) + parent.send(notification) + } + } +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt new file mode 100644 index 000000000..dc1e7637f --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +import org.jacodb.ifds.messages.AnalyzerMessage +import org.jacodb.ifds.messages.CommonMessage + +interface Analyzer { + fun step(message: AnalyzerMessage): Collection +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ApplicationGraph.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ApplicationGraph.kt new file mode 100644 index 000000000..1b7b1fb5f --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ApplicationGraph.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +interface ApplicationGraph { + fun predecessors(node: Statement): Sequence + fun successors(node: Statement): Sequence + + fun callees(node: Statement): Sequence + fun callers(method: Method): Sequence + + fun entryPoints(method: Method): Sequence + fun exitPoints(method: Method): Sequence + + fun methodOf(node: Statement): Method +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt new file mode 100644 index 000000000..b3cca8949 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +interface Chunk diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt new file mode 100644 index 000000000..a8320122b --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +data class Edge( + val from: Vertex, + val to: Vertex +) \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt new file mode 100644 index 000000000..d176a9425 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +interface FlowFunction { + fun FlowScope.sequent( + next: Stmt, + ) + + fun FlowScope.callToReturn( + returnSite: Stmt, + ) + + fun FlowScope.callToStart( + calleeStart: Stmt, + ) + + fun FlowScope.exitToReturnSite( + callerEdge: Edge, + returnSite: Stmt, + ) +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt new file mode 100644 index 000000000..1fc11369b --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +import org.jacodb.ifds.messages.CommonMessage + +class FlowScope( + val edge: Edge, + private val messages: MutableList, +) { + fun add(message: CommonMessage) { + messages.add(message) + } + + fun addAll(messages: Collection) { + this.messages.addAll(messages) + } +} \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt new file mode 100644 index 000000000..6308a6eb4 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.Factory +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.IndirectionMessage + +interface IfdsContext { + fun chunkByMessage(message: CommonMessage): Chunk + fun runnerTypeByMessage(message: CommonMessage): RunnerType + + fun getAnalyzer(chunk: Chunk, type: RunnerType): Analyzer + fun indirectionHandlerFactory(parent: ActorRef): Factory +} \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerType.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerType.kt new file mode 100644 index 000000000..a04ddd64a --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerType.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +interface RunnerType \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt new file mode 100644 index 000000000..c577f10e3 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +data class Vertex( + val stmt: Stmt, + val fact: Fact +) \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt new file mode 100644 index 000000000..e5b84bd1f --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.messages + +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.RunnerType + +interface AnalyzerMessage : CommonMessage + +data class EdgeMessage( + val edge: Edge +) : AnalyzerMessage + +data class ResolvedCall( + val edge: Edge, + val method: Method +) : AnalyzerMessage + +data class NotificationOnStart( + val runnerType: RunnerType, + val author: RunnerType, + val edge: Edge, + val data: Edge, +) : AnalyzerMessage + +data class NotificationOnEnd( + val runnerType: RunnerType, + val author: RunnerType, + val edge: Edge, + val data: Edge +) : AnalyzerMessage diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt new file mode 100644 index 000000000..273c505c2 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.messages + +sealed interface CommonMessage \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt new file mode 100644 index 000000000..2029422e7 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.messages + +import org.jacodb.ifds.domain.Edge + +interface IndirectionMessage : CommonMessage + +data class UnresolvedCall( + val edge: Edge +) : IndirectionMessage diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt new file mode 100644 index 000000000..7a4662dd0 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.messages + +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.domain.Vertex +import kotlinx.coroutines.channels.Channel + +sealed interface StorageMessage : CommonMessage + +data class NewEdge( + val runnerType: RunnerType, + val edge: Edge, + val reason: Edge, +) : StorageMessage + +data class NewSummaryEdge( + val runnerType: RunnerType, + val edge: Edge, +) : StorageMessage + +data class SubscriptionOnStart( + val runnerType: RunnerType, + val startVertex: Vertex, + val subscriber: RunnerType, + val data: Edge, +) : StorageMessage + +data class SubscriptionOnEnd( + val runnerType: RunnerType, + val endVertex: Vertex, + val subscriber: RunnerType, + val data: Edge, +) : StorageMessage + +data class NewResult( + val author: RunnerType, + val result: Any?, +) : StorageMessage + +data class ObtainResults( + val channel: Channel> +) : StorageMessage \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index d8aec8ff1..5df0a59fc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,7 @@ rootProject.name = "jacodb" plugins { `gradle-enterprise` id("org.danilopianini.gradle-pre-commit-git-hooks") version "1.1.11" + id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0" } gradleEnterprise { @@ -27,3 +28,5 @@ include("jacodb-benchmarks") include("jacodb-cli") include("jacodb-approximations") include("jacodb-taint-configuration") +include("jacodb-ifds:actors") +include("jacodb-ifds:ifds") From 5e9b7cf9d87f7fd126105c0e586a5a881aa0efb9 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 28 Mar 2024 12:43:01 +0300 Subject: [PATCH 02/64] [ifds] fix: function to property --- jacodb-ifds/actors/src/main/kotlin/Main.kt | 4 ++-- .../src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt | 2 +- .../kotlin/org/jacodb/actors/api/options/SpawnOptions.kt | 5 +---- .../kotlin/org/jacodb/actors/impl/ActorContextImpl.kt | 3 +-- .../main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt | 2 +- .../kotlin/org/jacodb/actors/impl/routing/Builders.kt | 8 ++++---- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/jacodb-ifds/actors/src/main/kotlin/Main.kt b/jacodb-ifds/actors/src/main/kotlin/Main.kt index a1cecb5e2..ab1276d67 100644 --- a/jacodb-ifds/actors/src/main/kotlin/Main.kt +++ b/jacodb-ifds/actors/src/main/kotlin/Main.kt @@ -85,7 +85,7 @@ class Root : Actor { private val producers = List(PRODUCERS) { spawn( "producer#$it", - SpawnOptions.default().channelFactory(buffered(32768)) + SpawnOptions.default.channelFactory(buffered(32768)) ) { Producer(consumers, iterations = CNT, sleep = SLEEP, it) } @@ -109,7 +109,7 @@ class Root : Actor { private val logger = logger("Main") suspend fun main() { - val system = systemOf("example", SpawnOptions.default(), ::Root) + val system = systemOf("example", SpawnOptions.default, ::Root) val ms = measureTimeMillis { system.send(RootMessage.Start) system.awaitTermination() diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt index 6b4c39a0f..bda2bdef3 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt @@ -21,7 +21,7 @@ import org.jacodb.actors.api.options.SpawnOptions interface ActorSpawner { fun spawn( name: String, - options: SpawnOptions = SpawnOptions.default(), + options: SpawnOptions = SpawnOptions.default, factory: Factory, ): ActorRef diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt index cefd4f24c..e396b5762 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt @@ -40,12 +40,9 @@ data class SpawnOptions( ) companion object { - private val default = SpawnOptions( + val default = SpawnOptions( ChannelFactory.unlimited(), EmptyCoroutineContext ) - - fun default(): SpawnOptions = - default } } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt index 906408094..89eb6bf0e 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt @@ -16,13 +16,12 @@ package org.jacodb.actors.impl +import mu.KLogger import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorSpawner import org.jacodb.actors.api.Factory import org.jacodb.actors.impl.workers.ActorWorker -import kotlinx.coroutines.channels.Channel -import mu.KLogger import kotlin.coroutines.CoroutineContext internal class ActorContextImpl( diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 5ffd20f84..4be89c3dc 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -68,7 +68,7 @@ internal class ActorSystemImpl( fun systemOf( name: String, - options: SpawnOptions = SpawnOptions.default(), + options: SpawnOptions = SpawnOptions.default, factory: Factory, ): ActorSystem = ActorSystemImpl( name, diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt index 8917f2744..3b8f9f058 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt @@ -21,7 +21,7 @@ import org.jacodb.actors.api.options.SpawnOptions fun roundRobinRouter( size: Int = 8, - routeeSpawnOptions: SpawnOptions = SpawnOptions.default(), + routeeSpawnOptions: SpawnOptions = SpawnOptions.default, routeeFactory: Factory, ) = Factory { RoundRobinRouter(size, routeeSpawnOptions, routeeFactory) @@ -29,7 +29,7 @@ fun roundRobinRouter( fun firstReadyRouter( size: Int = 8, - routeeSpawnOptions: SpawnOptions = SpawnOptions.default(), + routeeSpawnOptions: SpawnOptions = SpawnOptions.default, routeeFactory: Factory, ) = Factory { FirstReadyRouter(size, routeeSpawnOptions, routeeFactory) @@ -37,7 +37,7 @@ fun firstReadyRouter( fun randomRouter( size: Int = 8, - routeeSpawnOptions: SpawnOptions = SpawnOptions.default(), + routeeSpawnOptions: SpawnOptions = SpawnOptions.default, routeeFactory: Factory, ) = Factory { RandomRouter(size, routeeSpawnOptions, routeeFactory) @@ -46,7 +46,7 @@ fun randomRouter( fun messageKeyRouter( keyExtractor: (Message) -> Key, routeeNameFactory: (Key) -> String = { it.toString() }, - routeeSpawnOptions: SpawnOptions = SpawnOptions.default(), + routeeSpawnOptions: SpawnOptions = SpawnOptions.default, routeeFactory: KeyRouteeFactory ) = Factory { MessageKeyRouter(keyExtractor, routeeNameFactory, routeeSpawnOptions, routeeFactory) From 6edef8fbcefe7f08638af4553cca28b3d706aab5 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 28 Mar 2024 12:50:19 +0300 Subject: [PATCH 03/64] [ifds] fix: useless class --- .../jacodb/ifds/domain/ApplicationGraph.kt | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ApplicationGraph.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ApplicationGraph.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ApplicationGraph.kt deleted file mode 100644 index 1b7b1fb5f..000000000 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ApplicationGraph.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.domain - -interface ApplicationGraph { - fun predecessors(node: Statement): Sequence - fun successors(node: Statement): Sequence - - fun callees(node: Statement): Sequence - fun callers(method: Method): Sequence - - fun entryPoints(method: Method): Sequence - fun exitPoints(method: Method): Sequence - - fun methodOf(node: Statement): Method -} From 9f69164bcd3eafe0b4f0cd6905f23466ef9eb0c6 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 28 Mar 2024 14:52:54 +0300 Subject: [PATCH 04/64] [ifds] style: renamings --- .../jacodb/actors/api/options/SpawnOptions.kt | 8 +-- .../jacodb/actors/impl/routing/Builders.kt | 2 +- .../org/jacodb/ifds/actors/ChunkManager.kt | 4 +- .../org/jacodb/ifds/actors/ProjectManager.kt | 2 +- .../kotlin/org/jacodb/ifds/actors/Runner.kt | 47 ++++++++++--- .../org/jacodb/ifds/actors/RunnerManager.kt | 67 ------------------- .../kotlin/org/jacodb/ifds/actors/Worker.kt | 38 +++++++++++ 7 files changed, 84 insertions(+), 84 deletions(-) delete mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerManager.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt index e396b5762..f9b4c0c47 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt @@ -20,21 +20,21 @@ import kotlinx.coroutines.channels.Channel import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext -data class SpawnOptions( +class SpawnOptions( val channelFactory: ChannelFactory, val coroutineContext: CoroutineContext, ) { - fun channelFactory(channelFactory: ChannelFactory) = copy( + fun channelFactory(channelFactory: ChannelFactory) = SpawnOptions( channelFactory = channelFactory, coroutineContext = coroutineContext ) - fun channel(channel: Channel) = copy( + fun channel(channel: Channel) = SpawnOptions( channelFactory = { channel }, coroutineContext = coroutineContext ) - fun coroutineContext(coroutineContext: CoroutineContext) = copy( + fun coroutineContext(coroutineContext: CoroutineContext) = SpawnOptions( channelFactory = channelFactory, coroutineContext = coroutineContext ) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt index 3b8f9f058..e95e7e893 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt @@ -50,4 +50,4 @@ fun messageKeyRouter( routeeFactory: KeyRouteeFactory ) = Factory { MessageKeyRouter(keyExtractor, routeeNameFactory, routeeSpawnOptions, routeeFactory) -} \ No newline at end of file +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt index 86356e833..264a20cc6 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt @@ -34,11 +34,11 @@ class ChunkManager( private val routerFactory = messageKeyRouter( ifdsContext::runnerTypeByMessage ) { runnerType -> - RunnerManager(this@ActorContext.self, ifdsContext, chunk, runnerType) + Runner(this@ActorContext.self, ifdsContext, chunk, runnerType) } private val router = spawn( - "router", + "runners", factory = routerFactory ) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt index a18b6449a..02d4c9359 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt @@ -30,7 +30,7 @@ class ProjectManager( keyExtractor = ifdsContext::chunkByMessage ) { chunk -> ChunkManager(ifdsContext, chunk, this@ActorContext.self) } - private val router = spawn("router", factory = routerFactory) + private val router = spawn("chunks", factory = routerFactory) override suspend fun receive(message: CommonMessage) { router.send(message) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt index a3673cd9b..8f115cc1c 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt @@ -19,20 +19,49 @@ package org.jacodb.ifds.actors import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef -import org.jacodb.ifds.domain.Analyzer +import org.jacodb.actors.impl.routing.firstReadyRouter +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.domain.IfdsContext +import org.jacodb.ifds.domain.RunnerType import org.jacodb.ifds.messages.AnalyzerMessage import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.IndirectionMessage +import org.jacodb.ifds.messages.StorageMessage -context(ActorContext>) +context(ActorContext) class Runner( - private val analyzer: Analyzer, private val parent: ActorRef, -) : Actor> { + private val ifdsContext: IfdsContext, + private val chunk: Chunk, + private val runnerType: RunnerType, +) : Actor { + private val routerFactory = firstReadyRouter(size = 8) { + Worker(ifdsContext.getAnalyzer(chunk, runnerType), this@ActorContext.self) + } + + private val router = spawn("workers", factory = routerFactory) + + private val storage = spawn("storage") { + RunnerStorage(this@ActorContext.self, runnerType) + } + + private val indirectionHandler = spawn( + "indirection", + factory = ifdsContext.indirectionHandlerFactory(self) + ) + + override suspend fun receive(message: CommonMessage) { + when { + ifdsContext.chunkByMessage(message) == chunk && ifdsContext.runnerTypeByMessage(message) == runnerType -> { + @Suppress("UNCHECKED_CAST") + when (message) { + is StorageMessage -> storage.send(message) + is AnalyzerMessage<*, *> -> router.send(message as AnalyzerMessage) + is IndirectionMessage -> indirectionHandler.send(message) + } + } - override suspend fun receive(message: AnalyzerMessage) { - val newMessages = analyzer.step(message) - for (newMessage in newMessages) { - parent.send(newMessage) + else -> parent.send(message) } } -} \ No newline at end of file +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerManager.kt deleted file mode 100644 index 6dc69fea1..000000000 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerManager.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.actors - -import org.jacodb.actors.api.Actor -import org.jacodb.actors.api.ActorContext -import org.jacodb.actors.api.ActorRef -import org.jacodb.actors.impl.routing.firstReadyRouter -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.domain.IfdsContext -import org.jacodb.ifds.domain.RunnerType -import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.CommonMessage -import org.jacodb.ifds.messages.IndirectionMessage -import org.jacodb.ifds.messages.StorageMessage - -context(ActorContext) -class RunnerManager( - private val parent: ActorRef, - private val ifdsContext: IfdsContext, - private val chunk: Chunk, - private val runnerType: RunnerType, -) : Actor { - private val routerFactory = firstReadyRouter(size = 8) { - Runner(ifdsContext.getAnalyzer(chunk, runnerType), this@ActorContext.self) - } - - private val router = spawn("router", factory = routerFactory) - - private val storage = spawn("storage") { - RunnerStorage(this@ActorContext.self, runnerType) - } - - private val indirectionHandler = spawn( - "indirection", - factory = ifdsContext.indirectionHandlerFactory(self) - ) - - override suspend fun receive(message: CommonMessage) { - when { - ifdsContext.chunkByMessage(message) == chunk && ifdsContext.runnerTypeByMessage(message) == runnerType -> { - @Suppress("UNCHECKED_CAST") - when (message) { - is StorageMessage -> storage.send(message) - is AnalyzerMessage<*, *> -> router.send(message as AnalyzerMessage) - is IndirectionMessage -> indirectionHandler.send(message) - } - } - - else -> parent.send(message) - } - } -} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt new file mode 100644 index 000000000..99a5168ef --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.actors + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.ifds.domain.Analyzer +import org.jacodb.ifds.messages.AnalyzerMessage +import org.jacodb.ifds.messages.CommonMessage + +context(ActorContext>) +class Worker( + private val analyzer: Analyzer, + private val parent: ActorRef, +) : Actor> { + + override suspend fun receive(message: AnalyzerMessage) { + val newMessages = analyzer.step(message) + for (newMessage in newMessages) { + parent.send(newMessage) + } + } +} \ No newline at end of file From dd8e2a7675565f797d2266a0688b974062de9684 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Fri, 29 Mar 2024 14:58:26 +0300 Subject: [PATCH 05/64] [ifds] fix: remove `Message` interface --- .../org/jacodb/analysis/impl/IfdsNpeTest.kt | 2 +- .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 27 +++--- jacodb-ifds/actors/src/main/kotlin/Main.kt | 14 +-- .../org/jacodb/actors/api/ActorStatus.kt | 4 +- .../org/jacodb/actors/api/ActorSystem.kt | 2 +- .../jacodb/actors/impl/ActorContextImpl.kt | 10 +-- .../org/jacodb/actors/impl/ActorRefImpl.kt | 8 +- .../jacodb/actors/impl/ActorSpawnerImpl.kt | 42 ++++++--- .../org/jacodb/actors/impl/ActorSystemImpl.kt | 22 +++-- .../jacodb/actors/impl/InternalMessages.kt | 21 ----- .../kotlin/org/jacodb/actors/impl/Message.kt | 24 ------ .../actors/impl/routing/FirstReadyRouter.kt | 4 +- .../jacodb/actors/impl/workers/ActorWorker.kt | 12 +-- .../impl/workers/InternalActorWorker.kt | 26 ++---- .../actors/impl/workers/UserActorWorker.kt | 86 +++++++------------ 15 files changed, 118 insertions(+), 186 deletions(-) delete mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/InternalMessages.kt delete mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/Message.kt diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt index 8667fa1f6..d5e4d934a 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt @@ -221,7 +221,7 @@ class IfdsNpeTest : BaseAnalysisTest() { } } - system.awaitTermination() + system.awaitCompletion() val results = system.ack { ObtainResults(it) } results.map { it as TaintVulnerability } } diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index fef7f1901..9ac39fb87 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -16,16 +16,10 @@ package org.jacodb.analysis.impl -import org.jacodb.actors.impl.systemOf -import org.jacodb.ifds.actors.ProjectManager -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.ObtainResults -import org.jacodb.ifds.taint.TaintIfdsContext import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import org.jacodb.actors.impl.systemOf import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.ClassUnitResolver @@ -37,13 +31,18 @@ import org.jacodb.analysis.taint.toSarif import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods +import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.ObtainResults +import org.jacodb.ifds.taint.TaintIfdsContext import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.impl.features.usagesExt import org.jacodb.testing.WithDB import org.jacodb.testing.analysis.SqlInjectionExamples import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.RepeatedTest import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments @@ -104,7 +103,7 @@ class IfdsSqlTest : BaseAnalysisTest() { } } - system.awaitTermination() + system.awaitCompletion() val results = system.ack { ObtainResults(it) } results.map { it as TaintVulnerability } } @@ -114,19 +113,15 @@ class IfdsSqlTest : BaseAnalysisTest() { @MethodSource("provideClassesForJuliet89") fun `test on Juliet's CWE 89`(className: String) { testSingleJulietClass(className) { method -> - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - manager.analyze(listOf(method), timeout = 30.seconds) + findSinks(method) } } - @RepeatedTest(1000) + @Test fun `test on specific Juliet instance`() { val className = "juliet.testcases.CWE89_SQL_Injection.s01.CWE89_SQL_Injection__connect_tcp_execute_01" testSingleJulietClass(className) { method -> - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - manager.analyze(listOf(method), timeout = 30.seconds) + findSinks(method) } } diff --git a/jacodb-ifds/actors/src/main/kotlin/Main.kt b/jacodb-ifds/actors/src/main/kotlin/Main.kt index ab1276d67..071390a02 100644 --- a/jacodb-ifds/actors/src/main/kotlin/Main.kt +++ b/jacodb-ifds/actors/src/main/kotlin/Main.kt @@ -27,8 +27,8 @@ import mu.KotlinLogging.logger import java.util.concurrent.atomic.AtomicIntegerArray import kotlin.system.measureTimeMillis -const val CNT = 1_000_000 -const val SLEEP = 0L +const val CNT = 1_000 +const val SLEEP = 1L const val PRODUCERS = 10 class Msg(val id: Int, val x: Int) @@ -41,10 +41,10 @@ sealed interface ConsumerMessage { private var sums = AtomicIntegerArray(PRODUCERS) class Consumer( - total: Int, ) : Actor { override suspend fun receive(message: ConsumerMessage) { + delay(SLEEP) when (message) { is ConsumerMessage.Msg -> sums.addAndGet(message.id, message.x) is ConsumerMessage.Ack -> {} @@ -77,9 +77,9 @@ sealed interface RootMessage { context(ActorContext) class Root : Actor { // private val consumers = spawn("consumer") { Consumer(PRODUCERS) } - private val consumers = spawn("consumer", factory = firstReadyRouter(PRODUCERS) { - Consumer(PRODUCERS) - } + private val consumers = spawn( + "consumer", + factory = firstReadyRouter(2) { Consumer() } ) private val producers = List(PRODUCERS) { @@ -112,7 +112,7 @@ suspend fun main() { val system = systemOf("example", SpawnOptions.default, ::Root) val ms = measureTimeMillis { system.send(RootMessage.Start) - system.awaitTermination() + system.awaitCompletion() logger.info { List(PRODUCERS) { sums.get(it) } } } logger.info { "Finished in $ms" } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt index bb8a1ac20..049fb1171 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt @@ -17,6 +17,6 @@ package org.jacodb.actors.api enum class ActorStatus { - BUSY, - IDLE + IDLE, + BUSY } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt index b03a42058..c66c4a5c4 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt @@ -25,5 +25,5 @@ interface ActorSystem { suspend fun ack(messageBuilder: (Channel) -> Message): R - suspend fun awaitTermination() + suspend fun awaitCompletion() } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt index 89eb6bf0e..c4cb7252b 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt @@ -24,18 +24,18 @@ import org.jacodb.actors.api.Factory import org.jacodb.actors.impl.workers.ActorWorker import kotlin.coroutines.CoroutineContext -internal class ActorContextImpl( +internal class ActorContextImpl( private val spawner: ActorSpawner, - private val worker: ActorWorker, + private val worker: ActorWorker, override val logger: KLogger, -) : ActorContext, ActorSpawner by spawner { +) : ActorContext, ActorSpawner by spawner { - override val self: ActorRef + override val self: ActorRef get() = worker.self fun launch( coroutineContext: CoroutineContext, - factory: Factory, + factory: Factory, ) { val actor = factory.run { create() } worker.launchLoop(coroutineContext, actor) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt index b3b98ac1e..606570dc9 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt @@ -20,13 +20,13 @@ import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef import kotlinx.coroutines.channels.Channel -internal class ActorRefImpl( +internal class ActorRefImpl( override val path: ActorPath, private val channel: Channel, -) : ActorRef { +) : ActorRef { override fun toString(): String = "actor@$path" - internal suspend fun send(message: M) { - channel.send(UserMessage(message)) + internal suspend fun send(message: Message) { + channel.send(message) } } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt index 1b9d22a0e..0d4e96046 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt @@ -16,20 +16,20 @@ package org.jacodb.actors.impl +import kotlinx.coroutines.channels.Channel +import mu.KotlinLogging.logger import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorSpawner import org.jacodb.actors.api.Factory import org.jacodb.actors.api.options.SpawnOptions -import org.jacodb.actors.impl.workers.ActorWorker +import org.jacodb.actors.impl.workers.InternalActorWorker +import org.jacodb.actors.impl.workers.UserActorWorker import org.jacodb.actors.impl.workers.WorkerFactory -import kotlinx.coroutines.channels.Channel -import mu.KotlinLogging.logger internal class ActorSpawnerImpl( private val self: ActorPath, private val system: ActorSystemImpl<*>, - private val workerFactory: WorkerFactory, ) : ActorSpawner { private val children = hashMapOf>() @@ -37,16 +37,34 @@ internal class ActorSpawnerImpl( name: String, options: SpawnOptions, factory: Factory, + ): ActorRefImpl = + spawnImpl(name, options, factory) { ref, channel, system -> + UserActorWorker(ref, channel, system.scope, system.watcher) + } + + internal fun spawnInternalActor( + name: String, + options: SpawnOptions, + factory: Factory, + ): ActorRefImpl = + spawnImpl(name, options, factory) { ref, channel, system -> + InternalActorWorker(ref, channel, system.scope) + } + + private fun spawnImpl( + name: String, + options: SpawnOptions, + factory: Factory, + workerFactory: WorkerFactory, ): ActorRefImpl { @Suppress("UNCHECKED_CAST") - val channel = options.channelFactory.create() as Channel - val ref = createRef(name, channel) + val channel = options.channelFactory.create() as Channel + val ref = createRef(name, channel) - val spawner = ActorSpawnerImpl(ref.path, system, workerFactory) + val spawner = ActorSpawnerImpl(ref.path, system) - @Suppress("UNCHECKED_CAST") - val worker = workerFactory(ref, channel, system) as ActorWorker - val context = ActorContextImpl(spawner, worker, logger(ref.path.toString())) + val worker = workerFactory(ref, channel, system) + val context = ActorContextImpl(spawner, worker, logger(ref.toString())) context.launch(options.coroutineContext, factory) return ref @@ -54,13 +72,13 @@ internal class ActorSpawnerImpl( private fun createRef( name: String, - channel: Channel, + channel: Channel, ): ActorRefImpl { if (children[name] != null) { error("$self already has $name child") } val path = self / name - val ref = ActorRefImpl(path, channel) + val ref = ActorRefImpl(path, channel) children[name] = ref return ref } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 4be89c3dc..09cbe3d5e 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -16,16 +16,15 @@ package org.jacodb.actors.impl +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.channels.Channel import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.api.Factory import org.jacodb.actors.api.options.SpawnOptions import org.jacodb.actors.impl.actors.WatcherActor import org.jacodb.actors.impl.actors.WatcherMessage -import org.jacodb.actors.impl.workers.internalActorWorkerFactory -import org.jacodb.actors.impl.workers.userActorWorkerFactory -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.channels.Channel internal class ActorSystemImpl( override val name: String, @@ -34,14 +33,13 @@ internal class ActorSystemImpl( ) : ActorSystem { private val path = root() / name - private val userSpawner = ActorSpawnerImpl(path, this, userActorWorkerFactory) - private val internalSpawner = ActorSpawnerImpl(path, this, internalActorWorkerFactory) + private val spawner = ActorSpawnerImpl(path, this) internal val scope = CoroutineScope(SupervisorJob()) - internal val watcher = internalSpawner.spawn("watcher", factory = ::WatcherActor) + internal val watcher = spawner.spawnInternalActor("watcher", SpawnOptions.default, ::WatcherActor) - private val user = userSpawner.spawn("usr", options, factory) + private val user = spawner.spawn("usr", options, factory) override suspend fun send(message: Message) { watcher.send(WatcherMessage.OutOfSystemSend) @@ -57,9 +55,9 @@ internal class ActorSystemImpl( return received } - private val channel = Channel(capacity = Channel.RENDEZVOUS) - override suspend fun awaitTermination() { + override suspend fun awaitCompletion() { + val channel = Channel(capacity = 1, onBufferOverflow = BufferOverflow.SUSPEND) watcher.send(WatcherMessage.AwaitTermination(channel)) channel.receive() watcher.send(WatcherMessage.Idle) @@ -74,4 +72,4 @@ fun systemOf( name, options, factory -) \ No newline at end of file +) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/InternalMessages.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/InternalMessages.kt deleted file mode 100644 index d48f2b124..000000000 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/InternalMessages.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.actors.impl - -internal sealed interface InternalMessage : Message - -data object Die : InternalMessage \ No newline at end of file diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/Message.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/Message.kt deleted file mode 100644 index e540f55ac..000000000 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/Message.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.actors.impl - -internal sealed interface Message - -internal data class UserMessage( - val message: M, -) : Message - diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt index 1c41dc40d..151012284 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt @@ -20,8 +20,6 @@ import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.Factory import org.jacodb.actors.api.options.SpawnOptions -import org.jacodb.actors.impl.UserMessage - context(ActorContext) internal class FirstReadyRouter( @@ -42,6 +40,6 @@ internal class FirstReadyRouter( } override suspend fun receive(message: Message) { - channel.send(UserMessage(message)) + channel.send(message) } } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt index f48ff519a..f00564a5b 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt @@ -16,23 +16,23 @@ package org.jacodb.actors.impl.workers +import kotlinx.coroutines.channels.Channel import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorRef import org.jacodb.actors.impl.ActorRefImpl import org.jacodb.actors.impl.ActorSystemImpl -import org.jacodb.actors.impl.Message -import kotlinx.coroutines.channels.Channel import kotlin.coroutines.CoroutineContext -internal typealias WorkerFactory = (ActorRef<*>, Channel, ActorSystemImpl<*>) -> ActorWorker<*> +internal typealias WorkerFactory = + (ActorRef, Channel, ActorSystemImpl<*>) -> ActorWorker -internal interface ActorWorker { +internal interface ActorWorker { val channel: Channel - val self: ActorRef + val self: ActorRef fun launchLoop( coroutineContext: CoroutineContext, - actor: Actor, + actor: Actor, ) suspend fun send( diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt index 2b8eceade..ab0179815 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt @@ -16,25 +16,22 @@ package org.jacodb.actors.impl.workers -import org.jacodb.actors.api.Actor -import org.jacodb.actors.api.ActorRef -import org.jacodb.actors.impl.ActorRefImpl -import org.jacodb.actors.impl.Message -import org.jacodb.actors.impl.UserMessage import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.impl.ActorRefImpl import kotlin.coroutines.CoroutineContext - -internal class InternalActorWorker( - override val self: ActorRef, +internal class InternalActorWorker( + override val self: ActorRef, override val channel: Channel, private val scope: CoroutineScope, -) : ActorWorker { +) : ActorWorker { override fun launchLoop( coroutineContext: CoroutineContext, - actor: Actor, + actor: Actor, ) { scope.launch(coroutineContext) { loop(actor) @@ -46,15 +43,10 @@ internal class InternalActorWorker( } private suspend fun loop( - actor: Actor, + actor: Actor, ) { for (message in channel) { - @Suppress("UNCHECKED_CAST") - val userMessage = (message as UserMessage).message - actor.receive(userMessage) + actor.receive(message) } } } - -internal val internalActorWorkerFactory: WorkerFactory = - { self, channel, system -> InternalActorWorker(self, channel, system.scope) } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt index d8d1db1f4..fcdaf684e 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt @@ -16,48 +16,42 @@ package org.jacodb.actors.impl.workers +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.onClosed +import kotlinx.coroutines.channels.onSuccess +import kotlinx.coroutines.launch import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorStatus import org.jacodb.actors.api.signal.Signal import org.jacodb.actors.impl.ActorRefImpl -import org.jacodb.actors.impl.Die -import org.jacodb.actors.impl.InternalMessage -import org.jacodb.actors.impl.Message -import org.jacodb.actors.impl.UserMessage import org.jacodb.actors.impl.actors.Snapshot import org.jacodb.actors.impl.actors.WatcherMessage -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.onSuccess -import kotlinx.coroutines.launch -import mu.KotlinLogging.logger import kotlin.coroutines.CoroutineContext -internal class UserActorWorker( - override val self: ActorRef, +internal class UserActorWorker( + override val self: ActorRef, override val channel: Channel, private val scope: CoroutineScope, private val watcher: ActorRefImpl, -) : ActorWorker { +) : ActorWorker { private var received = 0 private var sent = 0 private var status = ActorStatus.IDLE - - private val handler = CoroutineExceptionHandler { _, it -> - System.err.println("$self: ${it.stackTraceToString()}") - } + private val job = Job() override fun launchLoop( coroutineContext: CoroutineContext, - actor: Actor, + actor: Actor, ) { - scope.launch(coroutineContext + handler) { + scope.launch(job) { sendInternal(watcher, WatcherMessage.Register(self)) loop(actor) + actor.receive(Signal.PostStop) } } @@ -71,63 +65,45 @@ internal class UserActorWorker( } private suspend fun loop( - actor: Actor, + actor: Actor, ) { - while (true) { - val receiveResult = channel.tryReceive() + var running = true + while (running) { + var receiveResult = channel.tryReceive() + if (receiveResult.isFailure) { + processEmptyChannel() + receiveResult = channel.receiveCatching() + } receiveResult + .onClosed { + processEmptyChannel() + running = false + } .onSuccess { message -> processMessage(actor, message) } - if (receiveResult.isFailure) { - processEmptyChannel() - val result = channel.receive() - processMessage(actor, result) - } } } private suspend fun processMessage( - actor: Actor, + actor: Actor, message: Message, ) { - @Suppress("UNCHECKED_CAST") - when (message) { - is UserMessage<*> -> processUserMessage(actor, message.message as M) - is InternalMessage -> processInternalMessage(actor, message) - } - } - - private suspend fun processEmptyChannel() { - if (status == ActorStatus.BUSY) { - status = ActorStatus.IDLE - val snapshot = WatcherMessage.UpdateSnapshot(self, Snapshot(status, sent, received)) - watcher.send(snapshot) - } - } - - private suspend fun processUserMessage(actor: Actor, message: M) { if (actor.flag) { received++ } - if (status == ActorStatus.IDLE) { status = ActorStatus.BUSY watcher.send(WatcherMessage.UpdateSnapshot(self, Snapshot(status, sent, received))) } - actor.receive(message) } - private suspend fun processInternalMessage(actor: Actor, message: InternalMessage) { - when (message) { - Die -> { - channel.close() - actor.receive(Signal.PostStop) - } + private suspend fun processEmptyChannel() { + if (status == ActorStatus.BUSY) { + status = ActorStatus.IDLE + val snapshot = WatcherMessage.UpdateSnapshot(self, Snapshot(status, sent, received)) + watcher.send(snapshot) } } } - -internal val userActorWorkerFactory: WorkerFactory = - { self, channel, system -> UserActorWorker(self, channel, system.scope, system.watcher) } From 979e956f847cf47dda695a74c19e9bbc7f32c81a Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Fri, 29 Mar 2024 15:30:18 +0300 Subject: [PATCH 06/64] [ifds] fix: remove `AckMessage` interface --- .../org/jacodb/actors/api/AckMessage.kt | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/AckMessage.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/AckMessage.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/AckMessage.kt deleted file mode 100644 index 697730aa4..000000000 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/AckMessage.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.actors.api - -interface AckMessage { - suspend fun get(): R - suspend fun put(result: R) -} \ No newline at end of file From 3880b3bccd6ffd8af50e04a1fc75de627530247f Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Fri, 29 Mar 2024 15:35:36 +0300 Subject: [PATCH 07/64] [ifds] fix: `ack` -> `ask` --- .../src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt | 2 +- .../src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt | 2 +- .../actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt | 2 +- .../src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt index d5e4d934a..df671f2be 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt @@ -222,7 +222,7 @@ class IfdsNpeTest : BaseAnalysisTest() { } system.awaitCompletion() - val results = system.ack { ObtainResults(it) } + val results = system.ask { ObtainResults(it) } results.map { it as TaintVulnerability } } diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index 9ac39fb87..09ec7a4c6 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -104,7 +104,7 @@ class IfdsSqlTest : BaseAnalysisTest() { } system.awaitCompletion() - val results = system.ack { ObtainResults(it) } + val results = system.ask { ObtainResults(it) } results.map { it as TaintVulnerability } } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt index c66c4a5c4..e467e6e2b 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt @@ -23,7 +23,7 @@ interface ActorSystem { suspend fun send(message: Message) - suspend fun ack(messageBuilder: (Channel) -> Message): R + suspend fun ask(messageBuilder: (Channel) -> Message): R suspend fun awaitCompletion() } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 09cbe3d5e..d6faa9189 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -46,7 +46,7 @@ internal class ActorSystemImpl( user.send(message) } - override suspend fun ack(messageBuilder: (Channel) -> Message): R { + override suspend fun ask(messageBuilder: (Channel) -> Message): R { watcher.send(WatcherMessage.OutOfSystemSend) val channel = Channel(Channel.RENDEZVOUS) val ack = messageBuilder(channel) From 7e765d441217bebecdb7b217890c4937f316f823 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 4 Apr 2024 16:57:17 +0300 Subject: [PATCH 08/64] [ifds] feat: reasons, `runnerId` property, `IfdsResult` --- .../TaintAnalyzer.kt => DefaultAnalyzer.kt} | 19 +-- .../ifds/{taint => }/FunctionWrapper.kt | 33 ++-- .../ifds/{taint => }/IndirectionHandler.kt | 10 +- .../kotlin/org/jacodb/ifds/JcIfdsContext.kt | 57 +++++++ .../kotlin/org/jacodb/ifds/npe/Context.kt | 67 ++++++++ .../kotlin/org/jacodb/ifds/npe/Results.kt | 31 ++++ .../kotlin/org/jacodb/ifds/npe/Runners.kt | 21 +++ .../org/jacodb/ifds/npe/SystemExtensions.kt | 50 ++++++ .../kotlin/org/jacodb/ifds/taint/Context.kt | 84 ++++++++++ .../kotlin/org/jacodb/ifds/taint/Results.kt | 31 ++++ .../kotlin/org/jacodb/ifds/taint/Runners.kt | 22 +++ .../org/jacodb/ifds/taint/SystemExtensions.kt | 59 +++++++ .../org/jacodb/ifds/taint/TaintIfdsContext.kt | 84 ---------- .../kotlin/org/jacodb/ifds/unused/Context.kt | 18 +++ .../jacodb/analysis/impl/BaseAnalysisTest.kt | 4 +- .../org/jacodb/analysis/impl/IfdsNpeTest.kt | 35 +--- .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 52 +++--- .../jacodb/analysis/impl/IfdsUnusedTest.kt | 25 +++ .../analysis/impl/JodaDateTimeAnalysisTest.kt | 21 ++- .../test/resources/simplelogger.properties | 4 +- .../org/jacodb/actors/impl/ActorSystemImpl.kt | 2 +- .../org/jacodb/ifds/actors/ChunkManager.kt | 12 +- .../kotlin/org/jacodb/ifds/actors/Runner.kt | 16 +- .../org/jacodb/ifds/actors/RunnerStorage.kt | 50 ++++-- .../ifds/domain/{Chunk.kt => ChunkId.kt} | 2 +- .../org/jacodb/ifds/domain/IfdsContext.kt | 8 +- .../kotlin/org/jacodb/ifds/domain/Reason.kt | 43 +++++ .../domain/{RunnerType.kt => RunnerId.kt} | 2 +- .../jacodb/ifds/messages/AnalyzerMessages.kt | 18 ++- .../jacodb/ifds/messages/CommonMessages.kt | 6 +- .../ifds/messages/IndirectionMessages.kt | 4 +- .../jacodb/ifds/messages/StorageMessages.kt | 32 ++-- .../jacodb/ifds/result/IfdsComputationData.kt | 35 ++++ .../org/jacodb/ifds/result/IfdsResult.kt | 23 +++ .../kotlin/org/jacodb/ifds/result/Merging.kt | 23 +++ .../ifds/result/SingleStorageTraceGraph.kt | 150 ++++++++++++++++++ .../org/jacodb/ifds/result/TraceGraph.kt | 30 ++++ 37 files changed, 942 insertions(+), 241 deletions(-) rename jacodb-analysis/src/main/kotlin/org/jacodb/ifds/{taint/TaintAnalyzer.kt => DefaultAnalyzer.kt} (89%) rename jacodb-analysis/src/main/kotlin/org/jacodb/ifds/{taint => }/FunctionWrapper.kt (75%) rename jacodb-analysis/src/main/kotlin/org/jacodb/ifds/{taint => }/IndirectionHandler.kt (90%) create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Results.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt delete mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintIfdsContext.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt rename jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/{Chunk.kt => ChunkId.kt} (97%) create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt rename jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/{RunnerType.kt => RunnerId.kt} (97%) create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/SingleStorageTraceGraph.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzer.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt similarity index 89% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzer.kt rename to jacodb-analysis/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt index 54c2f09f6..8e3d751f7 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzer.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt @@ -14,17 +14,16 @@ * limitations under the License. */ -package org.jacodb.ifds.taint +package org.jacodb.ifds import org.jacodb.ifds.domain.Analyzer import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.FlowFunction import org.jacodb.ifds.domain.FlowScope -import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.AnalyzerMessage import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.EdgeMessage -import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.messages.NotificationOnStart import org.jacodb.ifds.messages.ResolvedCall import org.jacodb.ifds.messages.UnresolvedCall @@ -35,10 +34,10 @@ import org.jacodb.api.ext.cfg.callExpr typealias TaintFlowScope = FlowScope -class TaintAnalyzer( +class DefaultAnalyzer( private val applicationGraph: JcApplicationGraph, private val flowFunction: FlowFunction, - private val runnerType: RunnerType, + private val runnerId: RunnerId, ) : Analyzer { override fun step(message: AnalyzerMessage): Collection = buildList { when (message) { @@ -73,13 +72,12 @@ class TaintAnalyzer( when { callExpr != null -> processCall(edge) - isExit -> processExit(edge) - else -> processSequent(edge) + !isExit -> processSequent(edge) } } private fun TaintFlowScope.processCall(edge: Edge) { - val callMessage = UnresolvedCall(edge) + val callMessage = UnresolvedCall(runnerId, edge) add(callMessage) val successors = applicationGraph.successors(edge.to.stmt) @@ -91,11 +89,6 @@ class TaintAnalyzer( } } - private fun TaintFlowScope.processExit(edge: Edge) { - val summaryEdge = NewSummaryEdge(runnerType, edge) - add(summaryEdge) - } - private fun TaintFlowScope.processSequent(edge: Edge) { val successors = applicationGraph.successors(edge.to.stmt) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/FunctionWrapper.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt similarity index 75% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/FunctionWrapper.kt rename to jacodb-analysis/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt index f97808960..ff12d2210 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/FunctionWrapper.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt @@ -14,23 +14,25 @@ * limitations under the License. */ -package org.jacodb.ifds.taint +package org.jacodb.ifds +import org.jacodb.analysis.ifds.Analyzer +import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.FlowFunction import org.jacodb.ifds.domain.FlowScope -import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.messages.SubscriptionOnStart -import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.api.cfg.JcInst +typealias JcEventProcessor = FlowScope.(Event) -> Unit class JcFlowFunctionsAdapter( - private val runnerType: RunnerType, + private val runnerId: RunnerId, private val jcAnalyzer: Analyzer, - private val jcEventProcessor: FlowScope.(Event) -> Unit, + private val jcEventProcessor: JcEventProcessor, ) : FlowFunction { private val jcFlowFunctions = jcAnalyzer.flowFunctions @@ -40,7 +42,7 @@ class JcFlowFunctionsAdapter( .compute(edge.to.fact) .forEach { newFact -> val newEdge = Edge(edge.from, Vertex(next, newFact)) - processNewEdge(runnerType, newEdge) + processNewEdge(runnerId, newEdge, Reason.Sequent(edge)) } override fun FlowScope.callToReturn(returnSite: JcInst) = @@ -49,7 +51,7 @@ class JcFlowFunctionsAdapter( .compute(edge.to.fact) .forEach { newFact -> val newEdge = Edge(edge.from, Vertex(returnSite, newFact)) - processNewEdge(runnerType, newEdge) + processNewEdge(runnerId, newEdge, Reason.CallToReturn(edge)) } override fun FlowScope.callToStart(calleeStart: JcInst) = @@ -59,11 +61,11 @@ class JcFlowFunctionsAdapter( .forEach { newFact -> val vertex = Vertex(calleeStart, newFact) - val subscription = SubscriptionOnStart(runnerType, vertex, runnerType, edge) + val subscription = SubscriptionOnStart(runnerId, vertex, runnerId, edge) add(subscription) val newEdge = Edge(vertex, vertex) - processNewEdge(runnerType, newEdge) + processNewEdge(runnerId, newEdge, Reason.CallToStart(edge)) } override fun FlowScope.exitToReturnSite( @@ -74,23 +76,26 @@ class JcFlowFunctionsAdapter( .compute(edge.to.fact) .forEach { newFact -> val newEdge = Edge(callerEdge.from, Vertex(returnSite, newFact)) - processNewEdge(runnerType, newEdge) + processNewEdge(runnerId, newEdge, Reason.ExitToReturnSite(callerEdge, edge)) } private fun FlowScope.processNewEdge( - runnerType: RunnerType, + runnerId: RunnerId, newEdge: Edge, + reason: Reason, ) { - val edge = NewEdge(runnerType, newEdge, edge) + val edge = NewEdge(runnerId, newEdge, reason) add(edge) val jcEvents = jcAnalyzer.handleNewEdge(newEdge.toJcEdge()) for (event in jcEvents) { jcEventProcessor(event) } - } } private fun Vertex.toJcVertex() = org.jacodb.analysis.ifds.Vertex(stmt, fact) private fun Edge.toJcEdge() = org.jacodb.analysis.ifds.Edge(from.toJcVertex(), to.toJcVertex()) + +fun org.jacodb.analysis.ifds.Vertex.toVertex() = Vertex(statement, fact) +fun org.jacodb.analysis.ifds.Edge.toEdge() = Edge(from.toVertex(), to.toVertex()) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/IndirectionHandler.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt similarity index 90% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/IndirectionHandler.kt rename to jacodb-analysis/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt index 65394297b..deb8508b6 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/IndirectionHandler.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.taint +package org.jacodb.ifds import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext @@ -27,6 +27,7 @@ import org.jacodb.api.cfg.JcVirtualCallExpr import org.jacodb.api.ext.HierarchyExtension import org.jacodb.api.ext.cfg.callExpr import org.jacodb.api.ext.isSubClassOf +import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.IndirectionMessage import org.jacodb.ifds.messages.ResolvedCall @@ -37,6 +38,7 @@ class IndirectionHandler( private val hierarchy: HierarchyExtension, private val bannedPackagePrefixes: List, private val parent: ActorRef, + private val runnerId: RunnerId, ) : Actor { private val cache = hashMapOf>() @@ -55,13 +57,13 @@ class IndirectionHandler( val callExpr = node.callExpr as? JcVirtualCallExpr if (callExpr == null) { for (override in callees) { - parent.send(ResolvedCall(message.edge, override)) + parent.send(ResolvedCall(runnerId, message.edge, override)) } return } val instanceClass = (callExpr.instance.type as? JcClassType)?.jcClass if (instanceClass == null) { - parent.send(ResolvedCall(message.edge, callExpr.method.method)) + parent.send(ResolvedCall(runnerId, message.edge, callExpr.method.method)) return } @@ -79,7 +81,7 @@ class IndirectionHandler( } for (override in overrides) { - parent.send(ResolvedCall(message.edge, override)) + parent.send(ResolvedCall(runnerId, message.edge, override)) } } } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt new file mode 100644 index 000000000..486963f93 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds + +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.Factory +import org.jacodb.api.JcClasspath +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Analyzer +import org.jacodb.ifds.domain.ChunkId +import org.jacodb.ifds.domain.FlowFunction +import org.jacodb.ifds.domain.IfdsContext +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.impl.features.HierarchyExtensionImpl + +class JcIfdsContext( + private val cp: JcClasspath, + private val graph: JcApplicationGraph, + private val bannedPackagePrefixes: List, + private val flowFunctionFactory: (ChunkId, RunnerId) -> FlowFunction, +) : IfdsContext { + data object SingleChunk : ChunkId + + override fun chunkByMessage(message: CommonMessage): ChunkId = + SingleChunk + + override fun runnerIdByMessage(message: CommonMessage): RunnerId = + message.runnerId + + override fun getAnalyzer(chunkId: ChunkId, runnerId: RunnerId): Analyzer = + DefaultAnalyzer( + graph, + flowFunctionFactory(chunkId, runnerId), + runnerId + ) + + override fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId) = + Factory { + IndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, parent, runnerId) + } +} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt new file mode 100644 index 000000000..a11c2a1ca --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.npe + +import org.jacodb.analysis.npe.NpeAnalyzer +import org.jacodb.analysis.taint.EdgeForOtherRunner +import org.jacodb.analysis.taint.NewVulnerability +import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.api.JcClasspath +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.ifds.JcFlowFunctionsAdapter +import org.jacodb.ifds.JcIfdsContext +import org.jacodb.ifds.messages.NewResult +import org.jacodb.ifds.messages.NewSummaryEdge +import org.jacodb.ifds.toEdge + +fun npeIfdsContext( + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List, +): JcIfdsContext = + JcIfdsContext( + cp, + graph, + bannedPackagePrefixes + ) { _, runnerId -> + val analyzer = when (runnerId) { + is SingleRunner -> NpeAnalyzer(graph) + else -> error("Unexpected runnerId: $runnerId") + } + + JcFlowFunctionsAdapter( + runnerId, + analyzer + ) { event -> + when (event) { + is EdgeForOtherRunner -> { + error("Unexpected event: $event") + } + + is org.jacodb.analysis.taint.NewSummaryEdge -> { + val summaryEdge = NewSummaryEdge(runnerId, event.edge.toEdge()) + add(summaryEdge) + } + + is NewVulnerability -> { + val result = NewResult(runnerId, NpeVulnerability(event.vulnerability)) + add(result) + } + } + } + } + diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt new file mode 100644 index 000000000..5568a927a --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.npe + +import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.analysis.taint.TaintVulnerability +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.toVertex +import org.jacodb.ifds.result.IfdsResult + +data class NpeVulnerability( + val vulnerability: TaintVulnerability, +) : IfdsResult { + override val vertex: Vertex + get() = vulnerability.sink.toVertex() +} \ No newline at end of file diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt new file mode 100644 index 000000000..55a43464c --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.npe + +import org.jacodb.ifds.domain.RunnerId + +data object SingleRunner : RunnerId \ No newline at end of file diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt new file mode 100644 index 000000000..4abfa303c --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.npe + +import org.jacodb.actors.api.ActorSystem +import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.npe.NpeAnalyzer +import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.analysis.taint.TaintVulnerability +import org.jacodb.api.JcMethod +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.ObtainData +import org.jacodb.impl.features.usagesExt + +suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { + val cp = method.enclosingClass.classpath + val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) + val npeAnalyzer = NpeAnalyzer(graph) + for (fact in npeAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { + for (entryPoint in graph.entryPoints(method)) { + val vertex = Vertex(entryPoint, fact) + val message = NewEdge(SingleRunner, Edge(vertex, vertex), Reason.Initial) + send(message) + } + } +} + +suspend fun ActorSystem.collectNpeResults(): List { + val ifdsComputationData = ask { ObtainData(SingleRunner, it) } + return ifdsComputationData.results.mapTo(mutableListOf()) { it.vulnerability } +} \ No newline at end of file diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt new file mode 100644 index 000000000..a94f9afd6 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.taint + +import org.jacodb.analysis.taint.BackwardTaintAnalyzer +import org.jacodb.analysis.taint.EdgeForOtherRunner +import org.jacodb.analysis.taint.NewVulnerability +import org.jacodb.analysis.taint.TaintAnalyzer +import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.api.JcClasspath +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.ifds.JcFlowFunctionsAdapter +import org.jacodb.ifds.JcIfdsContext +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.NewResult +import org.jacodb.ifds.messages.NewSummaryEdge +import org.jacodb.ifds.toEdge + +private fun complementRunner(type: RunnerId): RunnerId = + when (type) { + ForwardRunner -> BackwardRunner + BackwardRunner -> ForwardRunner + else -> error("unexpected runner: $type") + } + +fun taintIfdsContext( + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List, +): JcIfdsContext = + JcIfdsContext( + cp, + graph, + bannedPackagePrefixes + ) { _, runnerId -> + val analyzer = when (runnerId) { + is ForwardRunner -> TaintAnalyzer(graph) + is BackwardRunner -> BackwardTaintAnalyzer(graph) + else -> error("Unexpected runnerId: $runnerId") + } + + JcFlowFunctionsAdapter( + runnerId, + analyzer + ) { event -> + when (event) { + is EdgeForOtherRunner -> { + val edgeForOtherRunner = + NewEdge( + complementRunner(runnerId), + event.edge.toEdge(), + Reason.FromOtherRunner(edge, runnerId) + ) + add(edgeForOtherRunner) + } + + is org.jacodb.analysis.taint.NewSummaryEdge -> { + val summaryEdge = NewSummaryEdge(runnerId, event.edge.toEdge()) + add(summaryEdge) + } + + is NewVulnerability -> { + val result = NewResult(runnerId, TaintVulnerability(event.vulnerability)) + add(result) + } + } + } + } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Results.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Results.kt new file mode 100644 index 000000000..4f78a2ce1 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Results.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.taint + +import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.result.IfdsResult +import org.jacodb.ifds.toVertex +import org.jacodb.analysis.taint.TaintVulnerability as JcTaintVulnerability + +data class TaintVulnerability( + val vulnerability: JcTaintVulnerability, +) : IfdsResult { + override val vertex: Vertex + get() = vulnerability.sink.toVertex() +} \ No newline at end of file diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt new file mode 100644 index 000000000..2072ef83c --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.taint + +import org.jacodb.ifds.domain.RunnerId + +data object ForwardRunner : RunnerId +data object BackwardRunner : RunnerId \ No newline at end of file diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt new file mode 100644 index 000000000..5d728629a --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.taint + +import org.jacodb.actors.api.ActorSystem +import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.npe.NpeAnalyzer +import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.api.JcMethod +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.ObtainData +import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.impl.features.usagesExt + +suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { + val cp = method.enclosingClass.classpath + val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) + val npeAnalyzer = NpeAnalyzer(graph) + + for (fact in npeAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { + for (entryPoint in graph.entryPoints(method)) { + val vertex = Vertex(entryPoint, fact) + val message = NewEdge(ForwardRunner, Edge(vertex, vertex), Reason.Initial) + send(message) + } + } +} + +suspend fun ActorSystem.collectTaintResults(): List = + collectTaintComputationData() + .results + .mapTo(mutableListOf()) { it.vulnerability } + +suspend fun ActorSystem.collectTaintComputationData(): IfdsComputationData = + ask { + ObtainData( + ForwardRunner, + it + ) + } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintIfdsContext.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintIfdsContext.kt deleted file mode 100644 index 4878fb87f..000000000 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/TaintIfdsContext.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.taint - -import org.jacodb.actors.api.ActorRef -import org.jacodb.actors.api.Factory -import org.jacodb.ifds.domain.Analyzer -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.domain.IfdsContext -import org.jacodb.ifds.domain.RunnerType -import org.jacodb.ifds.messages.CommonMessage -import org.jacodb.ifds.messages.NewResult -import org.jacodb.analysis.taint.EdgeForOtherRunner -import org.jacodb.analysis.taint.NewSummaryEdge -import org.jacodb.analysis.taint.NewVulnerability -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintEvent -import org.jacodb.api.JcClasspath -import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.api.cfg.JcInst -import org.jacodb.impl.features.HierarchyExtensionImpl - -class TaintIfdsContext( - private val cp: JcClasspath, - private val graph: JcApplicationGraph, - private val jcAnalyzer: org.jacodb.analysis.ifds.Analyzer, - private val bannedPackagePrefixes: List, -) : IfdsContext { - data object Chunk1 : Chunk - data object Runner1 : RunnerType - - override fun chunkByMessage(message: CommonMessage): Chunk { - return Chunk1 - } - - override fun runnerTypeByMessage(message: CommonMessage): RunnerType { - return Runner1 - } - - override fun getAnalyzer(chunk: Chunk, type: RunnerType): Analyzer { - val wrapper = JcFlowFunctionsAdapter(Runner1, jcAnalyzer) { event -> - when (event) { - is EdgeForOtherRunner -> { - - } - - is NewSummaryEdge -> { - - } - - is NewVulnerability -> { - val result = NewResult(Runner1, event.vulnerability) - add(result) - } - } - } - - return TaintAnalyzer( - graph, - wrapper, - Runner1 - ) - } - - override fun indirectionHandlerFactory(parent: ActorRef) = - Factory { - IndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, parent) - } - -} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt new file mode 100644 index 000000000..05984a5fa --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.unused + diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt index e85491853..033b639c1 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt @@ -18,6 +18,7 @@ package org.jacodb.analysis.impl import juliet.support.AbstractTestCase import kotlinx.coroutines.runBlocking +import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.newApplicationGraphForAnalysis import org.jacodb.analysis.ifds.Vulnerability import org.jacodb.api.JcClasspath @@ -27,6 +28,7 @@ import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods import org.jacodb.impl.features.classpaths.UnknownClasses import org.jacodb.impl.features.hierarchyExt +import org.jacodb.impl.features.usagesExt import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.testing.BaseTest import org.jacodb.testing.WithGlobalDB @@ -100,7 +102,7 @@ abstract class BaseAnalysisTest : BaseTest() { protected val graph: JcApplicationGraph by lazy { runBlocking { - cp.newApplicationGraphForAnalysis() + JcApplicationGraphImpl(cp, cp.usagesExt()) } } diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt index df671f2be..b650fca49 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt @@ -16,21 +16,18 @@ package org.jacodb.analysis.impl -import org.jacodb.actors.impl.systemOf -import org.jacodb.ifds.actors.ProjectManager -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.ObtainResults -import org.jacodb.ifds.taint.TaintIfdsContext import kotlinx.coroutines.runBlocking +import org.jacodb.actors.impl.systemOf import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.npe.NpeAnalyzer import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.api.JcMethod import org.jacodb.api.ext.constructors import org.jacodb.api.ext.findClass +import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.npe.collectNpeResults +import org.jacodb.ifds.npe.npeIfdsContext +import org.jacodb.ifds.npe.startNpeAnalysis import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.impl.features.usagesExt @@ -202,28 +199,12 @@ class IfdsNpeTest : BaseAnalysisTest() { } private fun findSinks(method: JcMethod): List = runBlocking { - val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val npeAnalyzer = NpeAnalyzer(graph) - val ifdsContext = TaintIfdsContext( - cp, - graph, - npeAnalyzer, - defaultBannedPackagePrefixes - ) - + val ifdsContext = npeIfdsContext(cp, graph, defaultBannedPackagePrefixes) val system = systemOf("ifds") { ProjectManager(ifdsContext) } - for (fact in npeAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { - for (entryPoint in graph.entryPoints(method)) { - val vertex = Vertex(entryPoint, fact) - val message = NewEdge(TaintIfdsContext.Runner1, Edge(vertex, vertex), Edge(vertex, vertex)) - system.send(message) - } - } - + system.startNpeAnalysis(method) system.awaitCompletion() - val results = system.ask { ObtainResults(it) } - results.map { it as TaintVulnerability } + system.collectNpeResults() } @ParameterizedTest diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index 09ec7a4c6..607fd3163 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -20,26 +20,24 @@ import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.jacodb.actors.impl.systemOf -import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.ClassUnitResolver -import org.jacodb.analysis.ifds.SingletonUnitResolver import org.jacodb.analysis.sarif.sarifReportFromVulnerabilities import org.jacodb.analysis.taint.TaintManager import org.jacodb.analysis.taint.TaintVulnerability +import org.jacodb.analysis.taint.TaintZeroFact import org.jacodb.analysis.taint.toSarif import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods import org.jacodb.ifds.actors.ProjectManager -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.ObtainResults -import org.jacodb.ifds.taint.TaintIfdsContext +import org.jacodb.ifds.result.buildTraceGraph +import org.jacodb.ifds.taint.collectTaintComputationData +import org.jacodb.ifds.taint.collectTaintResults +import org.jacodb.ifds.taint.startTaintAnalysis +import org.jacodb.ifds.taint.taintIfdsContext import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages -import org.jacodb.impl.features.usagesExt import org.jacodb.testing.WithDB import org.jacodb.testing.analysis.SqlInjectionExamples import org.junit.jupiter.api.Assertions.assertTrue @@ -69,43 +67,31 @@ class IfdsSqlTest : BaseAnalysisTest() { } @Test - fun `simple SQL injection`() { + fun `simple SQL injection`() = runBlocking { val methodName = "bad" val method = cp.findClass().declaredMethods.single { it.name == methodName } - val methods = listOf(method) - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 30.seconds) + + val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) + val system = systemOf("ifds") { ProjectManager(ifdsContext) } + + system.startTaintAnalysis(method) + system.awaitCompletion() + val data = system.collectTaintComputationData() + val sinks = data.results assertTrue(sinks.isNotEmpty()) val sink = sinks.first() - val graph = manager.vulnerabilityTraceGraph(sink) + val graph = data.buildTraceGraph(sink.vertex, zeroFact = TaintZeroFact) val trace = graph.getAllTraces().first() assertTrue(trace.isNotEmpty()) } private fun findSinks(method: JcMethod): List = runBlocking { - val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val taintAnalyzer = org.jacodb.analysis.taint.TaintAnalyzer(graph) - val ifdsContext = TaintIfdsContext( - cp, - graph, - taintAnalyzer, - defaultBannedPackagePrefixes - ) - + val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) val system = systemOf("ifds") { ProjectManager(ifdsContext) } - for (fact in taintAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { - for (entryPoint in graph.entryPoints(method)) { - val vertex = Vertex(entryPoint, fact) - val message = NewEdge(TaintIfdsContext.Runner1, Edge(vertex, vertex), Edge(vertex, vertex)) - system.send(message) - } - } - + system.startTaintAnalysis(method) system.awaitCompletion() - val results = system.ask { ObtainResults(it) } - results.map { it as TaintVulnerability } + system.collectTaintResults() } diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt index e20442d2c..fc1d86516 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt @@ -55,6 +55,31 @@ class IfdsUnusedTest : BaseAnalysisTest() { ) } +// private fun findSinks(): List = runBlocking { +// val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) +// val unusedVariableAnalyzer = UnusedVariableAnalyzer(graph) +// val ifdsContext = JcIfdsContext( +// cp, +// graph, +// unusedVariableAnalyzer, +// defaultBannedPackagePrefixes +// ) +// +// val system = systemOf("ifds") { ProjectManager(ifdsContext) } +// +// for (fact in unusedVariableAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { +// for (entryPoint in graph.entryPoints(method)) { +// val vertex = Vertex(entryPoint, fact) +// val message = NewEdge(JcIfdsContext.ForwardRunner, Edge(vertex, vertex), Reason.Initial) +// system.send(message) +// } +// } +// +// system.awaitCompletion() +// val results = system.ask { ObtainData(JcIfdsContext.ForwardRunner, it) } +// results.map { it as UnusedVariableVulnerability } +// } + @ParameterizedTest @MethodSource("provideClassesForJuliet563") fun `test on Juliet's CWE 563`(className: String) { diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt index 8b3cb41c2..72a1c3725 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt @@ -17,14 +17,24 @@ package org.jacodb.analysis.impl import kotlinx.coroutines.runBlocking +import org.jacodb.actors.impl.systemOf +import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.graph.newApplicationGraphForAnalysis import org.jacodb.analysis.ifds.SingletonUnitResolver import org.jacodb.analysis.npe.NpeManager import org.jacodb.analysis.taint.TaintManager +import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.analysis.unused.UnusedVariableManager import org.jacodb.api.JcClasspath +import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.ext.findClass +import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.taint.collectTaintResults +import org.jacodb.ifds.taint.startTaintAnalysis +import org.jacodb.ifds.taint.taintIfdsContext +import org.jacodb.impl.features.usagesExt import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.testing.BaseTest import org.jacodb.testing.WithGlobalDB @@ -53,10 +63,19 @@ class JodaDateTimeAnalysisTest : BaseTest() { private val graph: JcApplicationGraph by lazy { runBlocking { - cp.newApplicationGraphForAnalysis() + JcApplicationGraphImpl(cp, cp.usagesExt()) } } + private fun findSinks(method: JcMethod): List = runBlocking { + val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) + val system = systemOf("ifds") { ProjectManager(ifdsContext) } + + system.startTaintAnalysis(method) + system.awaitCompletion() + system.collectTaintResults() + } + @Test fun `test taint analysis`() { val clazz = cp.findClass() diff --git a/jacodb-analysis/src/test/resources/simplelogger.properties b/jacodb-analysis/src/test/resources/simplelogger.properties index 36ae2abd2..e54e022a9 100644 --- a/jacodb-analysis/src/test/resources/simplelogger.properties +++ b/jacodb-analysis/src/test/resources/simplelogger.properties @@ -4,12 +4,12 @@ # Default logging detail level for all instances of SimpleLogger. # Must be one of ("trace", "debug", "info", "warn", or "error"). # If not specified, defaults to "info". -org.slf4j.simpleLogger.defaultLogLevel=error +org.slf4j.simpleLogger.defaultLogLevel=info # Logging detail level for a SimpleLogger instance named "xxxxx". # Must be one of ("trace", "debug", "info", "warn", or "error"). # If not specified, the default logging detail level is used. -org.slf4j.simpleLogger.log.org.jacodb.analysis.ifds=error +org.slf4j.simpleLogger.log.org.jacodb.analysis.ifds=info # Set to true if you want the current date and time to be included in output messages. # Default is false, and will output the number of milliseconds elapsed since startup. diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index d6faa9189..05bb8074d 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -48,7 +48,7 @@ internal class ActorSystemImpl( override suspend fun ask(messageBuilder: (Channel) -> Message): R { watcher.send(WatcherMessage.OutOfSystemSend) - val channel = Channel(Channel.RENDEZVOUS) + val channel = Channel(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) val ack = messageBuilder(channel) user.send(ack) val received = channel.receive() diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt index 264a20cc6..d83c8c079 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt @@ -20,21 +20,21 @@ import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorContext import org.jacodb.actors.impl.routing.messageKeyRouter -import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.domain.ChunkId import org.jacodb.ifds.domain.IfdsContext import org.jacodb.ifds.messages.CommonMessage context(ActorContext) class ChunkManager( private val ifdsContext: IfdsContext, - private val chunk: Chunk, + private val chunkId: ChunkId, private val parent: ActorRef, ) : Actor { private val routerFactory = messageKeyRouter( - ifdsContext::runnerTypeByMessage - ) { runnerType -> - Runner(this@ActorContext.self, ifdsContext, chunk, runnerType) + ifdsContext::runnerIdByMessage + ) { runnerId -> + Runner(this@ActorContext.self, ifdsContext, chunkId, runnerId) } private val router = spawn( @@ -44,7 +44,7 @@ class ChunkManager( override suspend fun receive(message: CommonMessage) { when { - chunk == ifdsContext.chunkByMessage(message) -> router.send(message) + chunkId == ifdsContext.chunkByMessage(message) -> router.send(message) else -> parent.send(message) } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt index 8f115cc1c..092b17e5f 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt @@ -20,9 +20,9 @@ import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.actors.impl.routing.firstReadyRouter -import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.domain.ChunkId import org.jacodb.ifds.domain.IfdsContext -import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.AnalyzerMessage import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.IndirectionMessage @@ -32,27 +32,27 @@ context(ActorContext) class Runner( private val parent: ActorRef, private val ifdsContext: IfdsContext, - private val chunk: Chunk, - private val runnerType: RunnerType, + private val chunkId: ChunkId, + private val runnerId: RunnerId, ) : Actor { private val routerFactory = firstReadyRouter(size = 8) { - Worker(ifdsContext.getAnalyzer(chunk, runnerType), this@ActorContext.self) + Worker(ifdsContext.getAnalyzer(chunkId, runnerId), this@ActorContext.self) } private val router = spawn("workers", factory = routerFactory) private val storage = spawn("storage") { - RunnerStorage(this@ActorContext.self, runnerType) + RunnerStorage(this@ActorContext.self, chunkId, runnerId) } private val indirectionHandler = spawn( "indirection", - factory = ifdsContext.indirectionHandlerFactory(self) + factory = ifdsContext.indirectionHandlerFactory(this@ActorContext.self, runnerId) ) override suspend fun receive(message: CommonMessage) { when { - ifdsContext.chunkByMessage(message) == chunk && ifdsContext.runnerTypeByMessage(message) == runnerType -> { + ifdsContext.chunkByMessage(message) == chunkId && ifdsContext.runnerIdByMessage(message) == runnerId -> { @Suppress("UNCHECKED_CAST") when (message) { is StorageMessage -> storage.send(message) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt index ce60efa3f..c074b5256 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt @@ -19,8 +19,10 @@ package org.jacodb.ifds.actors import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef +import org.jacodb.ifds.domain.ChunkId import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.EdgeMessage @@ -29,34 +31,37 @@ import org.jacodb.ifds.messages.NewResult import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.messages.NotificationOnEnd import org.jacodb.ifds.messages.NotificationOnStart -import org.jacodb.ifds.messages.ObtainResults +import org.jacodb.ifds.messages.ObtainData import org.jacodb.ifds.messages.StorageMessage import org.jacodb.ifds.messages.SubscriptionOnEnd import org.jacodb.ifds.messages.SubscriptionOnStart +import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.ifds.result.IfdsResult context(ActorContext) class RunnerStorage( private val parent: ActorRef, - private val runnerType: RunnerType, + private val chunkId: ChunkId, + private val runnerId: RunnerId, ) : Actor { data class SubscriptionData( val edge: Edge, - val subscriber: RunnerType, + val subscriber: RunnerId, ) - private val endSubscribers = - HashMap, HashSet>>() private val startSubscribers = HashMap, HashSet>>() + private val endSubscribers = + HashMap, HashSet>>() private val edges = hashSetOf>() - private val reasons = hashMapOf, HashSet>>() + private val reasons = hashMapOf, HashSet>>() private val summaryEdges = hashSetOf>() private val summaryEdgesByStart = hashMapOf, HashSet>>() private val summaryEdgesByEnd = hashMapOf, HashSet>>() - private val foundResults = hashSetOf() + private val foundResults = hashSetOf>() override suspend fun receive(message: StorageMessage) { when (message) { @@ -71,8 +76,7 @@ class RunnerStorage( if (edges.add(edge)) { // new edge - parent.send(EdgeMessage(edge)) - + parent.send(EdgeMessage(runnerId, edge)) } } @@ -121,12 +125,24 @@ class RunnerStorage( .add(subscriptionData) } - is NewResult -> { + is NewResult<*, *> -> { + @Suppress("UNCHECKED_CAST") + message as NewResult foundResults.add(message.result) } - is ObtainResults -> { - message.channel.send(foundResults.toList()) + is ObtainData<*, *, *> -> { + @Suppress("UNCHECKED_CAST") + message as ObtainData> + val data = IfdsComputationData( + chunkId, + runnerId, + edges.groupByTo(hashMapOf()) { it.to }, + edges.groupByTo(hashMapOf(), { it.to.stmt }) { it.to.fact }, + reasons.toMap(hashMapOf()), + foundResults.toHashSet() + ) + message.channel.send(data) } } } @@ -139,7 +155,7 @@ class RunnerStorage( for (summaryEdge in summaries) { val notification = NotificationOnStart( subscriptionData.subscriber, - runnerType, + runnerId, summaryEdge, subscriptionData.edge ) @@ -155,7 +171,7 @@ class RunnerStorage( for (summaryEdge in summaries) { val notification = NotificationOnEnd( subscriptionData.subscriber, - runnerType, + runnerId, summaryEdge, subscriptionData.edge ) @@ -171,7 +187,7 @@ class RunnerStorage( for ((data, subscriber) in currentEdgeStartSubscribers) { val notification = NotificationOnStart( subscriber, - runnerType, + runnerId, edge, data ) @@ -186,7 +202,7 @@ class RunnerStorage( for ((data, subscriber) in currentEdgeEndSubscribers) { val notification = NotificationOnEnd( subscriber, - runnerType, + runnerId, edge, data ) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ChunkId.kt similarity index 97% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt rename to jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ChunkId.kt index b3cca8949..39e11ab86 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ChunkId.kt @@ -16,4 +16,4 @@ package org.jacodb.ifds.domain -interface Chunk +interface ChunkId diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt index 6308a6eb4..480ae449f 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt @@ -22,9 +22,9 @@ import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.IndirectionMessage interface IfdsContext { - fun chunkByMessage(message: CommonMessage): Chunk - fun runnerTypeByMessage(message: CommonMessage): RunnerType + fun chunkByMessage(message: CommonMessage): ChunkId + fun runnerIdByMessage(message: CommonMessage): RunnerId - fun getAnalyzer(chunk: Chunk, type: RunnerType): Analyzer - fun indirectionHandlerFactory(parent: ActorRef): Factory + fun getAnalyzer(chunkId: ChunkId, runnerId: RunnerId): Analyzer + fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId): Factory } \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt new file mode 100644 index 000000000..b0d818916 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +sealed interface Reason { + data object Initial : Reason + + data class Sequent( + val edge: Edge, + ) : Reason + + data class CallToReturn( + val edge: Edge + ) : Reason + + data class CallToStart( + val edge: Edge, + ) : Reason + + data class ExitToReturnSite( + val callerEdge: Edge, + val edge: Edge, + ) : Reason + + data class FromOtherRunner( + val edge: Edge, + val otherRunnerId: RunnerId, + ) : Reason +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerType.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt similarity index 97% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerType.kt rename to jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt index a04ddd64a..9b4941308 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerType.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt @@ -16,4 +16,4 @@ package org.jacodb.ifds.domain -interface RunnerType \ No newline at end of file +interface RunnerId \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt index e5b84bd1f..d036cfed0 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt @@ -17,29 +17,31 @@ package org.jacodb.ifds.messages import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.domain.RunnerId interface AnalyzerMessage : CommonMessage data class EdgeMessage( - val edge: Edge + override val runnerId: RunnerId, + val edge: Edge, ) : AnalyzerMessage data class ResolvedCall( + override val runnerId: RunnerId, val edge: Edge, - val method: Method + val method: Method, ) : AnalyzerMessage data class NotificationOnStart( - val runnerType: RunnerType, - val author: RunnerType, + override val runnerId: RunnerId, + val author: RunnerId, val edge: Edge, val data: Edge, ) : AnalyzerMessage data class NotificationOnEnd( - val runnerType: RunnerType, - val author: RunnerType, + override val runnerId: RunnerId, + val author: RunnerId, val edge: Edge, - val data: Edge + val data: Edge, ) : AnalyzerMessage diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt index 273c505c2..71bfe6fe3 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt @@ -16,4 +16,8 @@ package org.jacodb.ifds.messages -sealed interface CommonMessage \ No newline at end of file +import org.jacodb.ifds.domain.RunnerId + +sealed interface CommonMessage { + val runnerId: RunnerId +} \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt index 2029422e7..123dfa53c 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt @@ -17,9 +17,11 @@ package org.jacodb.ifds.messages import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.RunnerId interface IndirectionMessage : CommonMessage data class UnresolvedCall( - val edge: Edge + override val runnerId: RunnerId, + val edge: Edge, ) : IndirectionMessage diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt index 7a4662dd0..5d7a2bade 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt @@ -17,42 +17,46 @@ package org.jacodb.ifds.messages import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.RunnerType +import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.domain.Vertex import kotlinx.coroutines.channels.Channel +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.ifds.result.IfdsResult sealed interface StorageMessage : CommonMessage data class NewEdge( - val runnerType: RunnerType, + override val runnerId: RunnerId, val edge: Edge, - val reason: Edge, + val reason: Reason, ) : StorageMessage data class NewSummaryEdge( - val runnerType: RunnerType, + override val runnerId: RunnerId, val edge: Edge, ) : StorageMessage data class SubscriptionOnStart( - val runnerType: RunnerType, + override val runnerId: RunnerId, val startVertex: Vertex, - val subscriber: RunnerType, + val subscriber: RunnerId, val data: Edge, ) : StorageMessage data class SubscriptionOnEnd( - val runnerType: RunnerType, + override val runnerId: RunnerId, val endVertex: Vertex, - val subscriber: RunnerType, + val subscriber: RunnerId, val data: Edge, ) : StorageMessage -data class NewResult( - val author: RunnerType, - val result: Any?, +data class NewResult( + override val runnerId: RunnerId, + val result: IfdsResult, ) : StorageMessage -data class ObtainResults( - val channel: Channel> -) : StorageMessage \ No newline at end of file +data class ObtainData>( + override val runnerId: RunnerId, + val channel: Channel>, +) : StorageMessage diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt new file mode 100644 index 000000000..cb9b5f686 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.result + +import org.jacodb.ifds.domain.ChunkId +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.domain.Vertex + +/** + * Aggregates all facts and edges found by the tabulation algorithm. + */ +data class IfdsComputationData>( + val chunkId: ChunkId, + val runnerId: RunnerId, + val edgesByEnd: Map, Collection>>, + val facts: Map>, + val reasons: Map, Collection>>, + val results: Collection, +) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt new file mode 100644 index 000000000..d0b3a71e7 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.result + +import org.jacodb.ifds.domain.Vertex + +interface IfdsResult { + val vertex: Vertex +} \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt new file mode 100644 index 000000000..d937af817 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.result + +fun > mergeIfdsResults( + ifdsResults: Collection>, +): IfdsComputationData { + TODO() +} \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/SingleStorageTraceGraph.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/SingleStorageTraceGraph.kt new file mode 100644 index 000000000..d76e5776d --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/SingleStorageTraceGraph.kt @@ -0,0 +1,150 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.result + +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.Vertex + +data class SingleStorageTraceGraph( + override val sink: Vertex, + override val sources: Set>, + override val edges: Map, MutableSet>>, +) : TraceGraph { + /** + * Returns all traces from [sources] to [sink]. + */ + override fun getAllTraces(): Sequence>> = sequence { + for (v in sources) { + yieldAll(getAllTraces(mutableListOf(v))) + } + } + + private fun getAllTraces( + trace: MutableList>, + ): Sequence>> = sequence { + val v = trace.last() + if (v == sink) { + yield(trace.toList()) // copy list + return@sequence + } + for (u in edges[v].orEmpty()) { + if (u !in trace) { + trace.add(u) + yieldAll(getAllTraces(trace)) + trace.removeLast() + } + } + } +} + +fun IfdsComputationData.buildTraceGraph( + sink: Vertex, + zeroFact: Fact? = null, +): TraceGraph { + val sources: MutableSet> = hashSetOf() + val edges: MutableMap, MutableSet>> = hashMapOf() + val visited: MutableSet, Vertex>> = hashSetOf() + + fun addEdge( + from: Vertex, + to: Vertex, + ) { + if (from != to) { + edges.getOrPut(from) { hashSetOf() }.add(to) + } + } + + fun dfs( + edge: Edge, + lastVertex: Vertex, + stopAtMethodStart: Boolean, + ) { + if (!visited.add(edge to lastVertex)) { + return + } + + // Note: loop-edge represents method start + if (stopAtMethodStart && edge.from == edge.to) { + addEdge(edge.from, lastVertex) + return + } + + val vertex = edge.to + if (vertex.fact == zeroFact) { + addEdge(vertex, lastVertex) + sources.add(vertex) + return + } + + for (reason in reasons[edge].orEmpty()) { + when (reason) { + Reason.Initial -> { + sources.add(vertex) + addEdge(edge.to, lastVertex) + } + + is Reason.Sequent -> { + val predEdge = reason.edge + if (predEdge.to.fact == vertex.fact) { + dfs(predEdge, lastVertex, stopAtMethodStart) + } else { + addEdge(predEdge.to, lastVertex) + dfs(predEdge, predEdge.to, stopAtMethodStart) + } + } + + is Reason.CallToReturn -> { + val predEdge = reason.edge + if (predEdge.to.fact == vertex.fact) { + dfs(predEdge, lastVertex, stopAtMethodStart) + } else { + addEdge(predEdge.to, lastVertex) + dfs(predEdge, predEdge.to, stopAtMethodStart) + } + } + + is Reason.CallToStart -> { + val predEdge = reason.edge + if (!stopAtMethodStart) { + addEdge(predEdge.to, lastVertex) + dfs(predEdge, predEdge.to, false) + } + } + + is Reason.ExitToReturnSite -> { + val predEdge = reason.callerEdge + val summaryEdge = reason.edge + addEdge(summaryEdge.from, lastVertex) + addEdge(predEdge.to, summaryEdge.from) + dfs(summaryEdge, summaryEdge.to, true) + dfs(predEdge, predEdge.to, stopAtMethodStart) + } + + is Reason.FromOtherRunner -> { + TODO("Reason from other runner is not supported yet") + } + } + } + } + + for (edge in edgesByEnd[sink].orEmpty()) { + dfs(edge, edge.to, false) + } + + return SingleStorageTraceGraph(sink, sources, edges) +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt new file mode 100644 index 000000000..19dbdcbb9 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.result + +import org.jacodb.ifds.domain.Vertex + +interface TraceGraph { + val sink: Vertex + val sources: Collection> + val edges: Map, Collection>> + + /** + * Returns all traces from [sources] to [sink]. + */ + fun getAllTraces(): Sequence>> +} \ No newline at end of file From e4138c08b72277429b1ef3b3c28085f27ab5e371 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Fri, 5 Apr 2024 11:30:04 +0300 Subject: [PATCH 09/64] [ifds] fix: revert `signPublication` --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4c7acff3d..1b1169c68 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -193,7 +193,7 @@ if (!repoUrl.isNullOrEmpty()) { groupId = "org.jacodb" artifactId = project.name addPom() -// signPublication(this@configure) + signPublication(this@configure) } } From 383f41dd8e416129ee85873708dd94f4c704fff7 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Fri, 5 Apr 2024 14:14:41 +0300 Subject: [PATCH 10/64] [ifds] feat: unused analyzer --- .../kotlin/org/jacodb/ifds/npe/Context.kt | 1 - .../kotlin/org/jacodb/ifds/npe/Results.kt | 2 +- .../kotlin/org/jacodb/ifds/npe/Runners.kt | 2 +- .../org/jacodb/ifds/npe/SystemExtensions.kt | 2 +- .../kotlin/org/jacodb/ifds/taint/Results.kt | 2 +- .../kotlin/org/jacodb/ifds/taint/Runners.kt | 2 +- .../org/jacodb/ifds/taint/SystemExtensions.kt | 4 +- .../kotlin/org/jacodb/ifds/unused/Context.kt | 35 ++++++++ .../kotlin/org/jacodb/ifds/unused/Results.kt | 31 +++++++ .../kotlin/org/jacodb/ifds/unused/Runners.kt | 21 +++++ .../jacodb/ifds/unused/SystemExtensions.kt | 84 +++++++++++++++++++ .../jacodb/analysis/impl/IfdsUnusedTest.kt | 52 +++++------- .../analysis/impl/JodaDateTimeAnalysisTest.kt | 65 +++++++------- 13 files changed, 234 insertions(+), 69 deletions(-) create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Results.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt index a11c2a1ca..3411218a0 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -64,4 +64,3 @@ fun npeIfdsContext( } } } - diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt index 5568a927a..fe7dd12a8 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt @@ -28,4 +28,4 @@ data class NpeVulnerability( ) : IfdsResult { override val vertex: Vertex get() = vulnerability.sink.toVertex() -} \ No newline at end of file +} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt index 55a43464c..e4865f7cd 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt @@ -18,4 +18,4 @@ package org.jacodb.ifds.npe import org.jacodb.ifds.domain.RunnerId -data object SingleRunner : RunnerId \ No newline at end of file +data object SingleRunner : RunnerId diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt index 4abfa303c..b99a028a2 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -47,4 +47,4 @@ suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { suspend fun ActorSystem.collectNpeResults(): List { val ifdsComputationData = ask { ObtainData(SingleRunner, it) } return ifdsComputationData.results.mapTo(mutableListOf()) { it.vulnerability } -} \ No newline at end of file +} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Results.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Results.kt index 4f78a2ce1..d8a82ed7c 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Results.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Results.kt @@ -28,4 +28,4 @@ data class TaintVulnerability( ) : IfdsResult { override val vertex: Vertex get() = vulnerability.sink.toVertex() -} \ No newline at end of file +} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt index 2072ef83c..e96d4c8d7 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt @@ -19,4 +19,4 @@ package org.jacodb.ifds.taint import org.jacodb.ifds.domain.RunnerId data object ForwardRunner : RunnerId -data object BackwardRunner : RunnerId \ No newline at end of file +data object BackwardRunner : RunnerId diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index 5d728629a..fed23d629 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -34,9 +34,9 @@ import org.jacodb.impl.features.usagesExt suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val npeAnalyzer = NpeAnalyzer(graph) + val taintAnalyzer = NpeAnalyzer(graph) - for (fact in npeAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { + for (fact in taintAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { val vertex = Vertex(entryPoint, fact) val message = NewEdge(ForwardRunner, Edge(vertex, vertex), Reason.Initial) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt index 05984a5fa..904372208 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt @@ -16,3 +16,38 @@ package org.jacodb.ifds.unused +import org.jacodb.analysis.unused.UnusedVariableAnalyzer +import org.jacodb.analysis.unused.UnusedVariableDomainFact +import org.jacodb.api.JcClasspath +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.ifds.JcFlowFunctionsAdapter +import org.jacodb.ifds.JcIfdsContext +import org.jacodb.ifds.toEdge + +fun unusedIfdsContext( + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List, +): JcIfdsContext = + JcIfdsContext( + cp, + graph, + bannedPackagePrefixes + ) { _, runnerId -> + val analyzer = when (runnerId) { + is SingleRunner -> UnusedVariableAnalyzer(graph) + else -> error("Unexpected runnerId: $runnerId") + } + + JcFlowFunctionsAdapter( + runnerId, + analyzer + ) { event -> + when (event) { + is org.jacodb.analysis.unused.NewSummaryEdge -> { + val edge = org.jacodb.ifds.messages.NewSummaryEdge(runnerId, event.edge.toEdge()) + add(edge) + } + } + } + } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Results.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Results.kt new file mode 100644 index 000000000..46200e2c7 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Results.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.unused + +import org.jacodb.analysis.unused.UnusedVariableDomainFact +import org.jacodb.analysis.unused.UnusedVariableVulnerability +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.result.IfdsResult +import org.jacodb.ifds.toVertex + +data class UnusedVulnerability( + val vulnerability: UnusedVariableVulnerability, +) : IfdsResult { + override val vertex: Vertex + get() = vulnerability.sink.toVertex() +} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt new file mode 100644 index 000000000..453b0d412 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.unused + +import org.jacodb.ifds.domain.RunnerId + +data object SingleRunner : RunnerId diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt new file mode 100644 index 000000000..af47edd23 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.unused + +import org.jacodb.actors.api.ActorSystem +import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.unused.UnusedVariable +import org.jacodb.analysis.unused.UnusedVariableAnalyzer +import org.jacodb.analysis.unused.UnusedVariableDomainFact +import org.jacodb.analysis.unused.UnusedVariableVulnerability +import org.jacodb.analysis.unused.UnusedVariableZeroFact +import org.jacodb.analysis.unused.isUsedAt +import org.jacodb.api.JcMethod +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.ObtainData +import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.impl.features.usagesExt + +suspend fun ActorSystem.startUnusedAnalysis(method: JcMethod) { + val cp = method.enclosingClass.classpath + val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) + val unusedAnalyzer = UnusedVariableAnalyzer(graph) + + for (fact in unusedAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { + for (entryPoint in graph.entryPoints(method)) { + val vertex = Vertex(entryPoint, fact) + val message = NewEdge(SingleRunner, Edge(vertex, vertex), Reason.Initial) + send(message) + } + } +} + +suspend fun ActorSystem.collectUnusedResult(): List { + val data = collectUnusedComputationData() + + val allFacts = data.facts + + val used = hashMapOf() + for ((inst, facts) in allFacts) { + for (fact in facts) { + if (fact is UnusedVariable) { + used.putIfAbsent(fact.initStatement, false) + if (fact.variable.isUsedAt(inst)) { + used[fact.initStatement] = true + } + } + + } + } + val vulnerabilities = used.filterValues { !it }.keys.map { + UnusedVariableVulnerability( + message = "Assigned value is unused", + sink = org.jacodb.analysis.ifds.Vertex(it, UnusedVariableZeroFact) + ) + } + return vulnerabilities +} + +suspend fun ActorSystem.collectUnusedComputationData(): IfdsComputationData = + ask { + ObtainData( + SingleRunner, + it + ) + } diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt index fc1d86516..e87dd16ad 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt @@ -16,10 +16,17 @@ package org.jacodb.analysis.impl -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.unused.UnusedVariableManager +import kotlinx.coroutines.runBlocking +import org.jacodb.actors.impl.systemOf +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.unused.UnusedVariableVulnerability +import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods +import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.unused.collectUnusedResult +import org.jacodb.ifds.unused.startUnusedAnalysis +import org.jacodb.ifds.unused.unusedIfdsContext import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.testing.WithDB @@ -29,7 +36,6 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource import java.util.stream.Stream -import kotlin.time.Duration.Companion.seconds class IfdsUnusedTest : BaseAnalysisTest() { @@ -55,38 +61,20 @@ class IfdsUnusedTest : BaseAnalysisTest() { ) } -// private fun findSinks(): List = runBlocking { -// val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) -// val unusedVariableAnalyzer = UnusedVariableAnalyzer(graph) -// val ifdsContext = JcIfdsContext( -// cp, -// graph, -// unusedVariableAnalyzer, -// defaultBannedPackagePrefixes -// ) -// -// val system = systemOf("ifds") { ProjectManager(ifdsContext) } -// -// for (fact in unusedVariableAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { -// for (entryPoint in graph.entryPoints(method)) { -// val vertex = Vertex(entryPoint, fact) -// val message = NewEdge(JcIfdsContext.ForwardRunner, Edge(vertex, vertex), Reason.Initial) -// system.send(message) -// } -// } -// -// system.awaitCompletion() -// val results = system.ask { ObtainData(JcIfdsContext.ForwardRunner, it) } -// results.map { it as UnusedVariableVulnerability } -// } + private fun findSinks(method: JcMethod): List = runBlocking { + val ifdsContext = unusedIfdsContext(cp, graph, defaultBannedPackagePrefixes) + val system = systemOf("ifds") { ProjectManager(ifdsContext) } + + system.startUnusedAnalysis(method) + system.awaitCompletion() + system.collectUnusedResult() + } @ParameterizedTest @MethodSource("provideClassesForJuliet563") fun `test on Juliet's CWE 563`(className: String) { testSingleJulietClass(className) { method -> - val unitResolver = SingletonUnitResolver - val manager = UnusedVariableManager(graph, unitResolver) - manager.analyze(listOf(method), timeout = 30.seconds) + findSinks(method) } } @@ -96,9 +84,7 @@ class IfdsUnusedTest : BaseAnalysisTest() { "juliet.testcases.CWE563_Unused_Variable.CWE563_Unused_Variable__unused_init_variable_StringBuilder_01" val clazz = cp.findClass(className) val badMethod = clazz.methods.single { it.name == "bad" } - val unitResolver = SingletonUnitResolver - val manager = UnusedVariableManager(graph, unitResolver) - val sinks = manager.analyze(listOf(badMethod), timeout = 30.seconds) + val sinks = findSinks(badMethod) Assertions.assertTrue(sinks.isNotEmpty()) } } diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt index 72a1c3725..900c916e9 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt @@ -20,20 +20,19 @@ import kotlinx.coroutines.runBlocking import org.jacodb.actors.impl.systemOf import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.graph.newApplicationGraphForAnalysis -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.npe.NpeManager -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.TaintVulnerability -import org.jacodb.analysis.unused.UnusedVariableManager import org.jacodb.api.JcClasspath -import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.ext.findClass import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.npe.collectNpeResults +import org.jacodb.ifds.npe.npeIfdsContext +import org.jacodb.ifds.npe.startNpeAnalysis import org.jacodb.ifds.taint.collectTaintResults import org.jacodb.ifds.taint.startTaintAnalysis import org.jacodb.ifds.taint.taintIfdsContext +import org.jacodb.ifds.unused.collectUnusedResult +import org.jacodb.ifds.unused.startUnusedAnalysis +import org.jacodb.ifds.unused.unusedIfdsContext import org.jacodb.impl.features.usagesExt import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.testing.BaseTest @@ -41,7 +40,6 @@ import org.jacodb.testing.WithGlobalDB import org.jacodb.testing.allClasspath import org.joda.time.DateTime import org.junit.jupiter.api.Test -import kotlin.time.Duration.Companion.seconds private val logger = mu.KotlinLogging.logger {} @@ -67,42 +65,53 @@ class JodaDateTimeAnalysisTest : BaseTest() { } } - private fun findSinks(method: JcMethod): List = runBlocking { + @Test + fun `test taint analysis`() = runBlocking { + val clazz = cp.findClass() + val methods = clazz.declaredMethods + val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) val system = systemOf("ifds") { ProjectManager(ifdsContext) } - system.startTaintAnalysis(method) + for (method in methods) { + system.startTaintAnalysis(method) + } system.awaitCompletion() - system.collectTaintResults() - } + val sinks = system.collectTaintResults() - @Test - fun `test taint analysis`() { - val clazz = cp.findClass() - val methods = clazz.declaredMethods - val unitResolver = SingletonUnitResolver - val manager = TaintManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 60.seconds) logger.info { "Vulnerabilities found: ${sinks.size}" } } @Test - fun `test NPE analysis`() { + fun `test NPE analysis`() = runBlocking { + // TODO: lacks timeout feature val clazz = cp.findClass() val methods = clazz.declaredMethods - val unitResolver = SingletonUnitResolver - val manager = NpeManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 60.seconds) + val ifdsContext = npeIfdsContext(cp, graph, defaultBannedPackagePrefixes) + val system = systemOf("ifds") { ProjectManager(ifdsContext) } + + for (method in methods) { + system.startNpeAnalysis(method) + } + system.awaitCompletion() + val sinks = system.collectNpeResults() + logger.info { "Vulnerabilities found: ${sinks.size}" } } @Test - fun `test unused variables analysis`() { + fun `test unused variables analysis`() = runBlocking { val clazz = cp.findClass() val methods = clazz.declaredMethods - val unitResolver = SingletonUnitResolver - val manager = UnusedVariableManager(graph, unitResolver) - val sinks = manager.analyze(methods, timeout = 60.seconds) - logger.info { "Unused variables found: ${sinks.size}" } + val ifdsContext = unusedIfdsContext(cp, graph, defaultBannedPackagePrefixes) + val system = systemOf("ifds") { ProjectManager(ifdsContext) } + + for (method in methods) { + system.startUnusedAnalysis(method) + } + system.awaitCompletion() + val sinks = system.collectUnusedResult() + + logger.info { "Vulnerabilities found: ${sinks.size}" } } } From bef6289ab66a3064c2fa6dcde071d7318b049335 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 9 Apr 2024 13:04:56 +0300 Subject: [PATCH 11/64] [ifds] feat: multi chunk + tests --- .../kotlin/org/jacodb/ifds/ChunkStrategies.kt | 60 +++++++++ .../kotlin/org/jacodb/ifds/DefaultAnalyzer.kt | 4 +- .../org/jacodb/ifds/IndirectionHandler.kt | 4 +- .../kotlin/org/jacodb/ifds/JcIfdsContext.kt | 22 ++- .../kotlin/org/jacodb/ifds/npe/Context.kt | 11 +- .../org/jacodb/ifds/npe/SystemExtensions.kt | 12 +- .../kotlin/org/jacodb/ifds/taint/Context.kt | 10 +- .../org/jacodb/ifds/taint/SystemExtensions.kt | 16 ++- .../kotlin/org/jacodb/ifds/unused/Context.kt | 9 +- .../jacodb/ifds/unused/SystemExtensions.kt | 15 ++- .../org/jacodb/actors/api/signal/Signal.kt | 1 + .../actors/impl/workers/UserActorWorker.kt | 1 + .../kotlin/org/jacodb/ifds/ChunkResolver.kt | 126 ++++++++++++++++++ .../jacodb/ifds/{domain => }/IfdsContext.kt | 15 ++- .../org/jacodb/ifds/actors/ChunkManager.kt | 32 +++-- .../org/jacodb/ifds/actors/ProjectManager.kt | 45 ++++++- .../kotlin/org/jacodb/ifds/actors/Runner.kt | 22 +-- .../org/jacodb/ifds/actors/RunnerStorage.kt | 8 +- .../kotlin/org/jacodb/ifds/actors/Worker.kt | 4 +- .../kotlin/org/jacodb/ifds/domain/Analyzer.kt | 4 +- .../ifds/domain/{ChunkId.kt => Chunk.kt} | 2 +- .../org/jacodb/ifds/domain/FlowScope.kt | 8 +- .../jacodb/ifds/messages/AnalyzerMessages.kt | 2 +- .../jacodb/ifds/messages/CommonMessages.kt | 4 +- .../ifds/messages/IndirectionMessages.kt | 2 +- .../jacodb/ifds/messages/ProjectMessages.kt | 33 +++++ .../jacodb/ifds/messages/StorageMessages.kt | 8 +- ...torageTraceGraph.kt => EagerTraceGraph.kt} | 4 +- .../jacodb/ifds/result/IfdsComputationData.kt | 3 - .../kotlin/org/jacodb/ifds/result/Merging.kt | 33 ++++- 30 files changed, 430 insertions(+), 90 deletions(-) create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt rename jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/{domain => }/IfdsContext.kt (66%) rename jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/{ChunkId.kt => Chunk.kt} (97%) create mode 100644 jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt rename jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/{SingleStorageTraceGraph.kt => EagerTraceGraph.kt} (97%) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt new file mode 100644 index 000000000..23b5abe09 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds + +import org.jacodb.api.JcClassOrInterface +import org.jacodb.api.JcMethod +import org.jacodb.api.cfg.JcInst +import org.jacodb.api.ext.packageName +import org.jacodb.ifds.domain.Chunk + +data object SingleChunk : Chunk + +val singleChunkStrategy = ChunkStrategy { + SingleChunk +} + +data class MethodChunk( + val method: JcMethod, +) : Chunk + +val MethodChunkStrategy = ChunkStrategy { + MethodChunk(it.location.method) +} + +data class ClassChunk( + val method: JcClassOrInterface, +) : Chunk + +val classChunkStrategy = ChunkStrategy { + val jcClass = it.location.method.enclosingClass + ClassChunk(jcClass) +} + +val classWithNestedChunkStrategy = ChunkStrategy { + val jClass = generateSequence(it.location.method.enclosingClass) { it.outerClass } + .last() + ClassChunk(jClass) +} + +data class PackageChunk( + val packageName: String, +) : Chunk + +val packageChunkStrategy = ChunkStrategy { + PackageChunk(it.location.method.enclosingClass.packageName) +} \ No newline at end of file diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt index 8e3d751f7..0693a577e 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt @@ -22,7 +22,7 @@ import org.jacodb.ifds.domain.FlowFunction import org.jacodb.ifds.domain.FlowScope import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.EdgeMessage import org.jacodb.ifds.messages.NotificationOnStart import org.jacodb.ifds.messages.ResolvedCall @@ -39,7 +39,7 @@ class DefaultAnalyzer( private val flowFunction: FlowFunction, private val runnerId: RunnerId, ) : Analyzer { - override fun step(message: AnalyzerMessage): Collection = buildList { + override fun step(message: AnalyzerMessage): Collection = buildList { when (message) { is EdgeMessage -> { val scope = TaintFlowScope(message.edge, this) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt index deb8508b6..1b2e89ef4 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt @@ -28,7 +28,7 @@ import org.jacodb.api.ext.HierarchyExtension import org.jacodb.api.ext.cfg.callExpr import org.jacodb.api.ext.isSubClassOf import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.IndirectionMessage import org.jacodb.ifds.messages.ResolvedCall import org.jacodb.ifds.messages.UnresolvedCall @@ -37,7 +37,7 @@ context(ActorContext) class IndirectionHandler( private val hierarchy: HierarchyExtension, private val bannedPackagePrefixes: List, - private val parent: ActorRef, + private val parent: ActorRef, private val runnerId: RunnerId, ) : Actor { private val cache = hashMapOf>() diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt index 486963f93..4d858c40c 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt @@ -22,35 +22,33 @@ import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Analyzer -import org.jacodb.ifds.domain.ChunkId +import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.domain.FlowFunction -import org.jacodb.ifds.domain.IfdsContext import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.impl.features.HierarchyExtensionImpl class JcIfdsContext( private val cp: JcClasspath, private val graph: JcApplicationGraph, private val bannedPackagePrefixes: List, - private val flowFunctionFactory: (ChunkId, RunnerId) -> FlowFunction, + private val chunkStrategy: ChunkResolver, + private val flowFunctionFactory: (RunnerId) -> FlowFunction, ) : IfdsContext { - data object SingleChunk : ChunkId + override fun chunkByMessage(message: RunnerMessage): Chunk = + chunkStrategy.chunkByMessage(message) - override fun chunkByMessage(message: CommonMessage): ChunkId = - SingleChunk - - override fun runnerIdByMessage(message: CommonMessage): RunnerId = + override fun runnerIdByMessage(message: RunnerMessage): RunnerId = message.runnerId - override fun getAnalyzer(chunkId: ChunkId, runnerId: RunnerId): Analyzer = + override fun getAnalyzer(chunk: Chunk, runnerId: RunnerId): Analyzer = DefaultAnalyzer( graph, - flowFunctionFactory(chunkId, runnerId), + flowFunctionFactory(runnerId), runnerId ) - override fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId) = + override fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId) = Factory { IndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, parent, runnerId) } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt index 3411218a0..b9daacfe3 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -22,8 +22,13 @@ import org.jacodb.analysis.taint.NewVulnerability import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.ChunkResolver +import org.jacodb.ifds.ChunkStrategy +import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext +import org.jacodb.ifds.MethodChunkStrategy import org.jacodb.ifds.messages.NewResult import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.toEdge @@ -32,12 +37,14 @@ fun npeIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List, + chunkStrategy: ChunkResolver = DefaultChunkResolver(MethodChunkStrategy), ): JcIfdsContext = JcIfdsContext( cp, graph, - bannedPackagePrefixes - ) { _, runnerId -> + bannedPackagePrefixes, + chunkStrategy + ) { runnerId -> val analyzer = when (runnerId) { is SingleRunner -> NpeAnalyzer(graph) else -> error("Unexpected runnerId: $runnerId") diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt index b99a028a2..556839341 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -26,9 +26,11 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.CollectAll import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.ObtainData +import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.ifds.result.mergeIfdsResults import org.jacodb.impl.features.usagesExt suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { @@ -45,6 +47,10 @@ suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { } suspend fun ActorSystem.collectNpeResults(): List { - val ifdsComputationData = ask { ObtainData(SingleRunner, it) } - return ifdsComputationData.results.mapTo(mutableListOf()) { it.vulnerability } + val results = ask { CollectAll(SingleRunner, it) } + + @Suppress("UNCHECKED_CAST") + val mergedData = + mergeIfdsResults(results.values as Collection>) + return mergedData.results.mapTo(mutableListOf()) { it.vulnerability } } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt index a94f9afd6..8cc3e7e39 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -23,8 +23,12 @@ import org.jacodb.analysis.taint.TaintAnalyzer import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.ifds.ChunkResolver +import org.jacodb.ifds.ChunkStrategy +import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext +import org.jacodb.ifds.MethodChunkStrategy import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.NewEdge @@ -43,12 +47,14 @@ fun taintIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List, + chunkStrategy: ChunkResolver = DefaultChunkResolver(MethodChunkStrategy), ): JcIfdsContext = JcIfdsContext( cp, graph, - bannedPackagePrefixes - ) { _, runnerId -> + bannedPackagePrefixes, + chunkStrategy + ) { runnerId -> val analyzer = when (runnerId) { is ForwardRunner -> TaintAnalyzer(graph) is BackwardRunner -> BackwardTaintAnalyzer(graph) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index fed23d629..61d36013f 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -25,10 +25,11 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.CollectAll import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.ObtainData import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.ifds.result.mergeIfdsResults import org.jacodb.impl.features.usagesExt suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { @@ -50,10 +51,17 @@ suspend fun ActorSystem.collectTaintResults(): List.collectTaintComputationData(): IfdsComputationData = - ask { - ObtainData( +suspend fun ActorSystem.collectTaintComputationData(): IfdsComputationData { + val results = ask { + CollectAll( ForwardRunner, it ) } + + @Suppress("UNCHECKED_CAST") + val mergedData = + mergeIfdsResults(results.values as Collection>) + + return mergedData +} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt index 904372208..7fdfdd822 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt @@ -20,20 +20,25 @@ import org.jacodb.analysis.unused.UnusedVariableAnalyzer import org.jacodb.analysis.unused.UnusedVariableDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.ifds.ChunkResolver +import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext +import org.jacodb.ifds.MethodChunkStrategy import org.jacodb.ifds.toEdge fun unusedIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List, + chunkStrategy: ChunkResolver = DefaultChunkResolver(MethodChunkStrategy), ): JcIfdsContext = JcIfdsContext( cp, graph, - bannedPackagePrefixes - ) { _, runnerId -> + bannedPackagePrefixes, + chunkStrategy + ) { runnerId -> val analyzer = when (runnerId) { is SingleRunner -> UnusedVariableAnalyzer(graph) else -> error("Unexpected runnerId: $runnerId") diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt index af47edd23..a61e7b155 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -29,10 +29,11 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.CollectAll import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.ObtainData import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.ifds.result.mergeIfdsResults import org.jacodb.impl.features.usagesExt suspend fun ActorSystem.startUnusedAnalysis(method: JcMethod) { @@ -75,10 +76,16 @@ suspend fun ActorSystem.collectUnusedResult(): List.collectUnusedComputationData(): IfdsComputationData = - ask { - ObtainData( +suspend fun ActorSystem.collectUnusedComputationData(): IfdsComputationData { + val results = ask { + CollectAll( SingleRunner, it ) } + + @Suppress("UNCHECKED_CAST") + val mergedData = + mergeIfdsResults(results.values as Collection>) + return mergedData +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt index 5c4a94c0e..bfabb169a 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt @@ -19,6 +19,7 @@ package org.jacodb.actors.api.signal import org.jacodb.actors.api.ActorRef sealed interface Signal { + data object Start : Signal data object PostStop : Signal class Terminated(val ref: ActorRef<*>) } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt index fcdaf684e..327c84324 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt @@ -50,6 +50,7 @@ internal class UserActorWorker( ) { scope.launch(job) { sendInternal(watcher, WatcherMessage.Register(self)) + actor.receive(Signal.Start) loop(actor) actor.receive(Signal.PostStop) } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt new file mode 100644 index 000000000..4fe3fbb97 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt @@ -0,0 +1,126 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds + +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.messages.AnalyzerMessage +import org.jacodb.ifds.messages.EdgeMessage +import org.jacodb.ifds.messages.IndirectionMessage +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.NewResult +import org.jacodb.ifds.messages.NewSummaryEdge +import org.jacodb.ifds.messages.NotificationOnEnd +import org.jacodb.ifds.messages.NotificationOnStart +import org.jacodb.ifds.messages.ObtainData +import org.jacodb.ifds.messages.ResolvedCall +import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.ifds.messages.StorageMessage +import org.jacodb.ifds.messages.SubscriptionOnEnd +import org.jacodb.ifds.messages.SubscriptionOnStart +import org.jacodb.ifds.messages.UnresolvedCall + + +fun interface ChunkResolver { + fun chunkByMessage(message: RunnerMessage): Chunk +} + +fun interface ChunkStrategy { + fun chunkByStmt(stmt: Stmt): Chunk +} + +class DefaultChunkResolver( + private val chunkStrategy: ChunkStrategy, +) : ChunkResolver { + @Suppress("UNCHECKED_CAST") + override fun chunkByMessage(message: RunnerMessage): Chunk = + when (message) { + is AnalyzerMessage<*, *> -> { + when (message) { + is EdgeMessage<*, *> -> { + message as EdgeMessage + chunkStrategy.chunkByStmt(message.edge.to.stmt) + } + + is NotificationOnEnd<*, *> -> { + message as NotificationOnEnd + chunkStrategy.chunkByStmt(message.edge.to.stmt) + } + + is NotificationOnStart<*, *> -> { + message as NotificationOnStart + chunkStrategy.chunkByStmt(message.edge.to.stmt) + } + + is ResolvedCall<*, *, *> -> { + message as ResolvedCall + chunkStrategy.chunkByStmt(message.edge.to.stmt) + } + + else -> { + error("Unexpected message: $message") + } + } + } + + is IndirectionMessage -> { + when (message) { + is UnresolvedCall<*, *> -> { + message as UnresolvedCall + chunkStrategy.chunkByStmt(message.edge.to.stmt) + } + + else -> { + error("Unexpected message: $message") + } + } + } + + is StorageMessage -> { + when (message) { + is NewEdge<*, *> -> { + message as NewEdge + chunkStrategy.chunkByStmt(message.edge.to.stmt) + } + + is NewResult<*, *> -> { + message as NewResult + chunkStrategy.chunkByStmt(message.result.vertex.stmt) + } + + is NewSummaryEdge<*, *> -> { + message as NewSummaryEdge + chunkStrategy.chunkByStmt(message.edge.to.stmt) + } + + is ObtainData<*, *, *> -> { + message as ObtainData + message.chunk + } + + is SubscriptionOnEnd<*, *> -> { + message as SubscriptionOnEnd + chunkStrategy.chunkByStmt(message.endVertex.stmt) + } + + is SubscriptionOnStart<*, *> -> { + message as SubscriptionOnStart + chunkStrategy.chunkByStmt(message.startVertex.stmt) + } + } + } + } +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt similarity index 66% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt rename to jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt index 480ae449f..9e824459e 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/IfdsContext.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt @@ -14,17 +14,20 @@ * limitations under the License. */ -package org.jacodb.ifds.domain +package org.jacodb.ifds import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.Factory -import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.domain.Analyzer +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.IndirectionMessage interface IfdsContext { - fun chunkByMessage(message: CommonMessage): ChunkId - fun runnerIdByMessage(message: CommonMessage): RunnerId + fun chunkByMessage(message: RunnerMessage): Chunk + fun runnerIdByMessage(message: RunnerMessage): RunnerId - fun getAnalyzer(chunkId: ChunkId, runnerId: RunnerId): Analyzer - fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId): Factory + fun getAnalyzer(chunk: Chunk, runnerId: RunnerId): Analyzer + fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId): Factory } \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt index d83c8c079..8ede7c23b 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt @@ -17,24 +17,27 @@ package org.jacodb.ifds.actors import org.jacodb.actors.api.Actor -import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.signal.Signal import org.jacodb.actors.impl.routing.messageKeyRouter -import org.jacodb.ifds.domain.ChunkId -import org.jacodb.ifds.domain.IfdsContext +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.IfdsContext import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.NewChunk +import org.jacodb.ifds.messages.RunnerMessage -context(ActorContext) +context(ActorContext) class ChunkManager( private val ifdsContext: IfdsContext, - private val chunkId: ChunkId, + private val chunk: Chunk, private val parent: ActorRef, -) : Actor { +) : Actor { private val routerFactory = messageKeyRouter( ifdsContext::runnerIdByMessage ) { runnerId -> - Runner(this@ActorContext.self, ifdsContext, chunkId, runnerId) + Runner(this@ActorContext.self, ifdsContext, chunk, runnerId) } private val router = spawn( @@ -42,11 +45,22 @@ class ChunkManager( factory = routerFactory ) - override suspend fun receive(message: CommonMessage) { + override suspend fun receive(message: RunnerMessage) { when { - chunkId == ifdsContext.chunkByMessage(message) -> router.send(message) + chunk == ifdsContext.chunkByMessage(message) -> router.send(message) else -> parent.send(message) } } + + override suspend fun receive(signal: Signal) { + when (signal) { + Signal.Start -> { + parent.send(NewChunk(chunk)) + } + Signal.PostStop -> { + + } + } + } } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt index 02d4c9359..bf741fc0b 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt @@ -16,11 +16,20 @@ package org.jacodb.ifds.actors +import kotlinx.coroutines.channels.Channel import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.impl.routing.messageKeyRouter -import org.jacodb.ifds.domain.IfdsContext +import org.jacodb.ifds.IfdsContext +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.messages.CollectAll import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.NewChunk +import org.jacodb.ifds.messages.ObtainData +import org.jacodb.ifds.messages.ProjectMessage +import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.ifds.result.IfdsResult context(ActorContext) class ProjectManager( @@ -32,7 +41,37 @@ class ProjectManager( private val router = spawn("chunks", factory = routerFactory) + private val chunks = hashSetOf() + override suspend fun receive(message: CommonMessage) { - router.send(message) + when (message) { + is RunnerMessage -> { + router.send(message) + } + + is ProjectMessage -> { + processProjectMessage(message) + } + } + } + + private suspend fun processProjectMessage(message: ProjectMessage) { + when (message) { + is NewChunk -> { + chunks.add(message.chunk) + } + + is CollectAll -> { + val results = hashMapOf>() + for (chunk in chunks) { + val channel = Channel>>() + val msg = ObtainData(chunk, message.runnerId, channel) + router.send(msg) + val data = channel.receive() + results[chunk] = data + } + message.channel.send(results) + } + } } -} \ No newline at end of file +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt index 092b17e5f..c3e7b82e4 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt @@ -20,29 +20,29 @@ import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.actors.impl.routing.firstReadyRouter -import org.jacodb.ifds.domain.ChunkId -import org.jacodb.ifds.domain.IfdsContext +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.IfdsContext import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.IndirectionMessage +import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.StorageMessage -context(ActorContext) +context(ActorContext) class Runner( - private val parent: ActorRef, + private val parent: ActorRef, private val ifdsContext: IfdsContext, - private val chunkId: ChunkId, + private val chunk: Chunk, private val runnerId: RunnerId, -) : Actor { +) : Actor { private val routerFactory = firstReadyRouter(size = 8) { - Worker(ifdsContext.getAnalyzer(chunkId, runnerId), this@ActorContext.self) + Worker(ifdsContext.getAnalyzer(chunk, runnerId), this@ActorContext.self) } private val router = spawn("workers", factory = routerFactory) private val storage = spawn("storage") { - RunnerStorage(this@ActorContext.self, chunkId, runnerId) + RunnerStorage(this@ActorContext.self, runnerId) } private val indirectionHandler = spawn( @@ -50,9 +50,9 @@ class Runner( factory = ifdsContext.indirectionHandlerFactory(this@ActorContext.self, runnerId) ) - override suspend fun receive(message: CommonMessage) { + override suspend fun receive(message: RunnerMessage) { when { - ifdsContext.chunkByMessage(message) == chunkId && ifdsContext.runnerIdByMessage(message) == runnerId -> { + ifdsContext.chunkByMessage(message) == chunk && ifdsContext.runnerIdByMessage(message) == runnerId -> { @Suppress("UNCHECKED_CAST") when (message) { is StorageMessage -> storage.send(message) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt index c074b5256..92ba4e1d1 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt @@ -19,12 +19,11 @@ package org.jacodb.ifds.actors import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef -import org.jacodb.ifds.domain.ChunkId import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.EdgeMessage import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.messages.NewResult @@ -40,8 +39,7 @@ import org.jacodb.ifds.result.IfdsResult context(ActorContext) class RunnerStorage( - private val parent: ActorRef, - private val chunkId: ChunkId, + private val parent: ActorRef, private val runnerId: RunnerId, ) : Actor { data class SubscriptionData( @@ -135,8 +133,6 @@ class RunnerStorage( @Suppress("UNCHECKED_CAST") message as ObtainData> val data = IfdsComputationData( - chunkId, - runnerId, edges.groupByTo(hashMapOf()) { it.to }, edges.groupByTo(hashMapOf(), { it.to.stmt }) { it.to.fact }, reasons.toMap(hashMapOf()), diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt index 99a5168ef..5f1f0b272 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt @@ -21,12 +21,12 @@ import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.ifds.domain.Analyzer import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.RunnerMessage context(ActorContext>) class Worker( private val analyzer: Analyzer, - private val parent: ActorRef, + private val parent: ActorRef, ) : Actor> { override suspend fun receive(message: AnalyzerMessage) { diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt index dc1e7637f..066207f2a 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt @@ -17,8 +17,8 @@ package org.jacodb.ifds.domain import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.RunnerMessage interface Analyzer { - fun step(message: AnalyzerMessage): Collection + fun step(message: AnalyzerMessage): Collection } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ChunkId.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt similarity index 97% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ChunkId.kt rename to jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt index 39e11ab86..b3cca8949 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/ChunkId.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt @@ -16,4 +16,4 @@ package org.jacodb.ifds.domain -interface ChunkId +interface Chunk diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt index 1fc11369b..ab439803b 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt @@ -16,17 +16,17 @@ package org.jacodb.ifds.domain -import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.RunnerMessage class FlowScope( val edge: Edge, - private val messages: MutableList, + private val messages: MutableList, ) { - fun add(message: CommonMessage) { + fun add(message: RunnerMessage) { messages.add(message) } - fun addAll(messages: Collection) { + fun addAll(messages: Collection) { this.messages.addAll(messages) } } \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt index d036cfed0..5cc0414c4 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt @@ -19,7 +19,7 @@ package org.jacodb.ifds.messages import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.RunnerId -interface AnalyzerMessage : CommonMessage +interface AnalyzerMessage : RunnerMessage data class EdgeMessage( override val runnerId: RunnerId, diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt index 71bfe6fe3..e650c85cf 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt @@ -18,6 +18,8 @@ package org.jacodb.ifds.messages import org.jacodb.ifds.domain.RunnerId -sealed interface CommonMessage { +sealed interface CommonMessage + +sealed interface RunnerMessage : CommonMessage { val runnerId: RunnerId } \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt index 123dfa53c..e2c445fbf 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt @@ -19,7 +19,7 @@ package org.jacodb.ifds.messages import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.RunnerId -interface IndirectionMessage : CommonMessage +interface IndirectionMessage : RunnerMessage data class UnresolvedCall( override val runnerId: RunnerId, diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt new file mode 100644 index 000000000..89cc51cc6 --- /dev/null +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.messages + +import kotlinx.coroutines.channels.Channel +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.result.IfdsComputationData + +sealed interface ProjectMessage : CommonMessage + +data class NewChunk( + val chunk: Chunk +) : ProjectMessage + +data class CollectAll( + val runnerId: RunnerId, + val channel: Channel>> +) : ProjectMessage \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt index 5d7a2bade..3619017f2 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt @@ -16,15 +16,16 @@ package org.jacodb.ifds.messages +import kotlinx.coroutines.channels.Channel +import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.domain.Vertex -import kotlinx.coroutines.channels.Channel -import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.IfdsResult -sealed interface StorageMessage : CommonMessage +sealed interface StorageMessage : RunnerMessage data class NewEdge( override val runnerId: RunnerId, @@ -57,6 +58,7 @@ data class NewResult( ) : StorageMessage data class ObtainData>( + val chunk: Chunk, override val runnerId: RunnerId, val channel: Channel>, ) : StorageMessage diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/SingleStorageTraceGraph.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt similarity index 97% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/SingleStorageTraceGraph.kt rename to jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt index d76e5776d..ac851834d 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/SingleStorageTraceGraph.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt @@ -20,7 +20,7 @@ import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex -data class SingleStorageTraceGraph( +data class EagerTraceGraph( override val sink: Vertex, override val sources: Set>, override val edges: Map, MutableSet>>, @@ -146,5 +146,5 @@ fun IfdsComputationData.buildTraceGraph( dfs(edge, edge.to, false) } - return SingleStorageTraceGraph(sink, sources, edges) + return EagerTraceGraph(sink, sources, edges) } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt index cb9b5f686..d52acbfd9 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt @@ -16,7 +16,6 @@ package org.jacodb.ifds.result -import org.jacodb.ifds.domain.ChunkId import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId @@ -26,8 +25,6 @@ import org.jacodb.ifds.domain.Vertex * Aggregates all facts and edges found by the tabulation algorithm. */ data class IfdsComputationData>( - val chunkId: ChunkId, - val runnerId: RunnerId, val edgesByEnd: Map, Collection>>, val facts: Map>, val reasons: Map, Collection>>, diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt index d937af817..6e2374651 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt @@ -16,8 +16,37 @@ package org.jacodb.ifds.result +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.Vertex + fun > mergeIfdsResults( - ifdsResults: Collection>, + ifdsDatas: Collection>, ): IfdsComputationData { - TODO() + val edgesByEnd = hashMapOf, HashSet>>() + val factsByStmt = hashMapOf>() + val reasonsByEdge = hashMapOf, HashSet>>() + val results = hashSetOf() + for (data in ifdsDatas) { + for ((end, edges) in data.edgesByEnd) { + edgesByEnd.getOrPut(end, ::hashSetOf) + .addAll(edges) + } + for ((stmt, facts) in data.facts) { + factsByStmt.getOrPut(stmt, ::hashSetOf) + .addAll(facts) + } + for ((edge, reasons) in data.reasons) { + reasonsByEdge.getOrPut(edge, ::hashSetOf) + .addAll(reasons) + } + results.addAll(data.results) + } + val mergedData = IfdsComputationData( + edgesByEnd, + factsByStmt, + reasonsByEdge, + results + ) + return mergedData } \ No newline at end of file From f8146fdc8464b056ef59a0947e38dddcb4090937 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Mon, 15 Apr 2024 10:31:47 +0300 Subject: [PATCH 12/64] [ifds] feat: graceful termination --- .../kotlin/org/jacodb/ifds/ChunkStrategies.kt | 8 +- .../kotlin/org/jacodb/ifds/JcIfdsContext.kt | 4 +- .../kotlin/org/jacodb/ifds/npe/Context.kt | 6 +- .../kotlin/org/jacodb/ifds/sarif/Sarif.kt | 150 ++++++++++++++++++ .../jacodb/ifds/sarif/SourceFileResolver.kt | 17 +- .../org/jacodb/ifds/sarif/Vulnerability.kt | 56 +++++++ .../kotlin/org/jacodb/ifds/taint/Context.kt | 22 +-- .../kotlin/org/jacodb/ifds/unused/Context.kt | 4 +- .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 23 +-- .../analysis/impl/JodaDateTimeAnalysisTest.kt | 14 +- jacodb-ifds/actors/src/main/kotlin/Main.kt | 119 -------------- .../kotlin/org/jacodb/actors/api/Actor.kt | 2 - .../org/jacodb/actors/api/ActorContext.kt | 2 +- .../api/{Factory.kt => ActorFactory.kt} | 2 +- .../kotlin/org/jacodb/actors/api/ActorRef.kt | 7 +- .../org/jacodb/actors/api/ActorSpawner.kt | 7 +- .../org/jacodb/actors/api/ActorSystem.kt | 4 + .../jacodb/actors/impl/ActorContextImpl.kt | 24 +-- .../jacodb/actors/impl/ActorSpawnerImpl.kt | 63 ++++---- .../org/jacodb/actors/impl/ActorSystemImpl.kt | 42 +++-- .../jacodb/actors/impl/actors/WatcherActor.kt | 27 ++-- .../actors/impl/actors/WatcherMessages.kt | 10 +- .../jacodb/actors/impl/routing/Builders.kt | 20 +-- .../actors/impl/routing/FirstReadyRouter.kt | 45 ------ .../actors/impl/routing/RandomRouter.kt | 4 +- .../actors/impl/routing/RoundRobinRouter.kt | 4 +- .../jacodb/actors/impl/workers/ActorWorker.kt | 22 +-- .../impl/workers/InternalActorWorker.kt | 23 ++- .../actors/impl/workers/UserActorWorker.kt | 65 +++++--- .../kotlin/org/jacodb/actors/StoppingTest.kt | 71 +++++++++ .../kotlin/org/jacodb/ifds/IfdsContext.kt | 4 +- .../org/jacodb/ifds/actors/ChunkManager.kt | 2 +- .../org/jacodb/ifds/actors/ProjectManager.kt | 2 +- .../kotlin/org/jacodb/ifds/actors/Runner.kt | 10 +- 34 files changed, 527 insertions(+), 358 deletions(-) create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt rename jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt => jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt (59%) create mode 100644 jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt delete mode 100644 jacodb-ifds/actors/src/main/kotlin/Main.kt rename jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/{Factory.kt => ActorFactory.kt} (95%) delete mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt create mode 100644 jacodb-ifds/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt index 23b5abe09..b73b97b07 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt @@ -24,7 +24,7 @@ import org.jacodb.ifds.domain.Chunk data object SingleChunk : Chunk -val singleChunkStrategy = ChunkStrategy { +val SingleChunkStrategy = ChunkStrategy { SingleChunk } @@ -40,12 +40,12 @@ data class ClassChunk( val method: JcClassOrInterface, ) : Chunk -val classChunkStrategy = ChunkStrategy { +val ClassChunkStrategy = ChunkStrategy { val jcClass = it.location.method.enclosingClass ClassChunk(jcClass) } -val classWithNestedChunkStrategy = ChunkStrategy { +val ClassWithNestedChunkStrategy = ChunkStrategy { val jClass = generateSequence(it.location.method.enclosingClass) { it.outerClass } .last() ClassChunk(jClass) @@ -55,6 +55,6 @@ data class PackageChunk( val packageName: String, ) : Chunk -val packageChunkStrategy = ChunkStrategy { +val PackageChunkStrategy = ChunkStrategy { PackageChunk(it.location.method.enclosingClass.packageName) } \ No newline at end of file diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt index 4d858c40c..a7a45efcc 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt @@ -17,7 +17,7 @@ package org.jacodb.ifds import org.jacodb.actors.api.ActorRef -import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.ActorFactory import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst @@ -49,7 +49,7 @@ class JcIfdsContext( ) override fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId) = - Factory { + ActorFactory { IndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, parent, runnerId) } } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt index b9daacfe3..1d4c74784 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -22,13 +22,11 @@ import org.jacodb.analysis.taint.NewVulnerability import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.ChunkResolver -import org.jacodb.ifds.ChunkStrategy +import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext -import org.jacodb.ifds.MethodChunkStrategy import org.jacodb.ifds.messages.NewResult import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.toEdge @@ -37,7 +35,7 @@ fun npeIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List, - chunkStrategy: ChunkResolver = DefaultChunkResolver(MethodChunkStrategy), + chunkStrategy: ChunkResolver = DefaultChunkResolver(ClassChunkStrategy), ): JcIfdsContext = JcIfdsContext( cp, diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt new file mode 100644 index 000000000..db71f2e34 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt @@ -0,0 +1,150 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.sarif + +import io.github.detekt.sarif4k.ArtifactLocation +import io.github.detekt.sarif4k.CodeFlow +import io.github.detekt.sarif4k.Location +import io.github.detekt.sarif4k.LogicalLocation +import io.github.detekt.sarif4k.Message +import io.github.detekt.sarif4k.MultiformatMessageString +import io.github.detekt.sarif4k.PhysicalLocation +import io.github.detekt.sarif4k.Region +import io.github.detekt.sarif4k.Result +import io.github.detekt.sarif4k.Run +import io.github.detekt.sarif4k.SarifSchema210 +import io.github.detekt.sarif4k.ThreadFlow +import io.github.detekt.sarif4k.ThreadFlowLocation +import io.github.detekt.sarif4k.Tool +import io.github.detekt.sarif4k.ToolComponent +import io.github.detekt.sarif4k.Version +import org.jacodb.api.JcMethod +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Vertex +import java.io.File + +private const val SARIF_SCHEMA = + "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json" +private const val JACODB_INFORMATION_URI = + "https://github.com/UnitTestBot/jacodb/blob/develop/jacodb-analysis/README.md" +private const val DEFAULT_PATH_COUNT = 3 + +fun sarifReportFromVulnerabilities( + vulnerabilities: List>, + maxPathsCount: Int = DEFAULT_PATH_COUNT, + isDeduplicate: Boolean = true, + sourceFileResolver: SourceFileResolver = SourceFileResolver { null }, +): SarifSchema210 { + return SarifSchema210( + schema = SARIF_SCHEMA, + version = Version.The210, + runs = listOf( + Run( + tool = Tool( + driver = ToolComponent( + name = "jacodb-analysis", + organization = "UnitTestBot", + version = "1.4.5", + informationURI = JACODB_INFORMATION_URI, + ) + ), + results = vulnerabilities.map { instance -> + Result( + ruleID = instance.description.ruleId, + message = Message( + text = instance.description.message + ), + level = instance.description.level, + locations = listOf(instToSarifLocation(instance.traceGraph.sink.stmt, sourceFileResolver)), + codeFlows = instance.traceGraph + .getAllTraces() + .take(maxPathsCount) + .map { traceToSarifCodeFlow(it, sourceFileResolver, isDeduplicate) } + .toList(), + ) + } + ) + ) + ) +} + +private val JcMethod.fullyQualifiedName: String + get() = "${enclosingClass.name}#${name}" + +private fun instToSarifLocation(inst: JcInst, sourceFileResolver: SourceFileResolver): Location { + val sourceLocation = sourceFileResolver.resolve(inst) + ?: run { + val registeredLocation = inst.location.method.declaration.location + val classFile = inst.location.method.enclosingClass.name + .replace('.', '/') + ".class" + File(registeredLocation.path).resolve(classFile).path + } + return Location( + physicalLocation = PhysicalLocation( + artifactLocation = ArtifactLocation( + uri = sourceLocation + ), + region = Region( + startLine = inst.location.lineNumber.toLong() + ) + ), + logicalLocations = listOf( + LogicalLocation( + fullyQualifiedName = inst.location.method.fullyQualifiedName + ) + ) + ) +} + +private fun traceToSarifCodeFlow( + trace: List>, + sourceFileResolver: SourceFileResolver, + isDeduplicate: Boolean = true, +): CodeFlow { + return CodeFlow( + threadFlows = listOf( + ThreadFlow( + locations = trace.map { + ThreadFlowLocation( + location = instToSarifLocation(it.stmt, sourceFileResolver), + state = mapOf( + "fact" to MultiformatMessageString( + text = it.fact.toString() + ) + ) + ) + }.let { + if (isDeduplicate) it.deduplicate() else it + } + ) + ) + ) +} + +private fun List.deduplicate(): List { + if (isEmpty()) return emptyList() + + return listOf(first()) + zipWithNext { a, b -> + val aLine = a.location!!.physicalLocation!!.region!!.startLine!! + val bLine = b.location!!.physicalLocation!!.region!!.startLine!! + if (aLine != bLine) { + b + } else { + null + } + }.filterNotNull() +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt similarity index 59% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt rename to jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt index 606570dc9..b9c3e4007 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorRefImpl.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt @@ -14,19 +14,10 @@ * limitations under the License. */ -package org.jacodb.actors.impl +package org.jacodb.ifds.sarif -import org.jacodb.actors.api.ActorPath -import org.jacodb.actors.api.ActorRef -import kotlinx.coroutines.channels.Channel +import org.jacodb.api.cfg.JcInst -internal class ActorRefImpl( - override val path: ActorPath, - private val channel: Channel, -) : ActorRef { - override fun toString(): String = "actor@$path" - - internal suspend fun send(message: Message) { - channel.send(message) - } +fun interface SourceFileResolver { + fun resolve(inst: JcInst): String? } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt new file mode 100644 index 000000000..b79b527f7 --- /dev/null +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.sarif + +import io.github.detekt.sarif4k.Level +import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.analysis.unused.UnusedVariableDomainFact +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.result.EagerTraceGraph +import org.jacodb.ifds.result.TraceGraph +import org.jacodb.ifds.taint.TaintVulnerability +import org.jacodb.ifds.unused.UnusedVulnerability + +data class VulnerabilityInstance( + val traceGraph: TraceGraph, + val description: VulnerabilityDescription, +) + +data class VulnerabilityDescription( + val ruleId: String?, + val message: String?, + val level: Level = Level.Warning, +) + +fun UnusedVulnerability.toSarif(): VulnerabilityInstance { + return VulnerabilityInstance( + EagerTraceGraph(vertex, mutableSetOf(vertex), mutableMapOf()), + VulnerabilityDescription(ruleId = null, message = vulnerability.message) + ) +} + +fun TaintVulnerability.toSarif( + graph: TraceGraph, +): VulnerabilityInstance { + return VulnerabilityInstance( + graph, + VulnerabilityDescription( + ruleId = null, + message = this.vulnerability.rule?.ruleNote + ) + ) +} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt index 8cc3e7e39..506672b98 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -24,11 +24,10 @@ import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.ifds.ChunkResolver -import org.jacodb.ifds.ChunkStrategy +import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext -import org.jacodb.ifds.MethodChunkStrategy import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.NewEdge @@ -47,7 +46,8 @@ fun taintIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List, - chunkStrategy: ChunkResolver = DefaultChunkResolver(MethodChunkStrategy), + chunkStrategy: ChunkResolver = DefaultChunkResolver(ClassChunkStrategy), + useBackwardRunner: Boolean = false, ): JcIfdsContext = JcIfdsContext( cp, @@ -67,13 +67,15 @@ fun taintIfdsContext( ) { event -> when (event) { is EdgeForOtherRunner -> { - val edgeForOtherRunner = - NewEdge( - complementRunner(runnerId), - event.edge.toEdge(), - Reason.FromOtherRunner(edge, runnerId) - ) - add(edgeForOtherRunner) + if (useBackwardRunner) { + val edgeForOtherRunner = + NewEdge( + complementRunner(runnerId), + event.edge.toEdge(), + Reason.FromOtherRunner(edge, runnerId) + ) + add(edgeForOtherRunner) + } } is org.jacodb.analysis.taint.NewSummaryEdge -> { diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt index 7fdfdd822..fe0ec732a 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt @@ -21,17 +21,17 @@ import org.jacodb.analysis.unused.UnusedVariableDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.ifds.ChunkResolver +import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext -import org.jacodb.ifds.MethodChunkStrategy import org.jacodb.ifds.toEdge fun unusedIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List, - chunkStrategy: ChunkResolver = DefaultChunkResolver(MethodChunkStrategy), + chunkStrategy: ChunkResolver = DefaultChunkResolver(ClassChunkStrategy), ): JcIfdsContext = JcIfdsContext( cp, diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index 607fd3163..da36ed237 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -21,17 +21,15 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.jacodb.actors.impl.systemOf import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.ifds.ClassUnitResolver -import org.jacodb.analysis.sarif.sarifReportFromVulnerabilities -import org.jacodb.analysis.taint.TaintManager import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.analysis.taint.toSarif import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.result.buildTraceGraph +import org.jacodb.ifds.sarif.sarifReportFromVulnerabilities +import org.jacodb.ifds.sarif.toSarif import org.jacodb.ifds.taint.collectTaintComputationData import org.jacodb.ifds.taint.collectTaintResults import org.jacodb.ifds.taint.startTaintAnalysis @@ -46,7 +44,6 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource import java.util.stream.Stream -import kotlin.time.Duration.Companion.seconds private val logger = mu.KotlinLogging.logger {} @@ -112,18 +109,24 @@ class IfdsSqlTest : BaseAnalysisTest() { } @Test - fun `test bidirectional runner and other stuff`() { + fun `test bidirectional runner and other stuff`() = runBlocking { val className = "juliet.testcases.CWE89_SQL_Injection.s01.CWE89_SQL_Injection__Environment_executeBatch_51a" val clazz = cp.findClass(className) val badMethod = clazz.methods.single { it.name == "bad" } - val unitResolver = ClassUnitResolver(true) - val manager = TaintManager(graph, unitResolver, useBidiRunner = true) - val sinks = manager.analyze(listOf(badMethod), timeout = 30.seconds) + + val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes, useBackwardRunner = true) + val system = systemOf("ifds") { ProjectManager(ifdsContext) } + + system.startTaintAnalysis(badMethod) + system.awaitCompletion() + val data = system.collectTaintComputationData() + val sinks = data.results assertTrue(sinks.isNotEmpty()) val sink = sinks.first() - val graph = manager.vulnerabilityTraceGraph(sink) + val graph = data.buildTraceGraph(sink.vertex, zeroFact = TaintZeroFact) val trace = graph.getAllTraces().first() assertTrue(trace.isNotEmpty()) + val sarif = sarifReportFromVulnerabilities(listOf(sink.toSarif(graph))) val sarifJson = myJson.encodeToString(sarif) logger.info { "SARIF:\n$sarifJson" } diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt index 900c916e9..92b93c1b5 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt @@ -16,6 +16,8 @@ package org.jacodb.analysis.impl +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.jacodb.actors.impl.systemOf import org.jacodb.analysis.graph.JcApplicationGraphImpl @@ -40,6 +42,7 @@ import org.jacodb.testing.WithGlobalDB import org.jacodb.testing.allClasspath import org.joda.time.DateTime import org.junit.jupiter.api.Test +import kotlin.time.Duration.Companion.seconds private val logger = mu.KotlinLogging.logger {} @@ -76,7 +79,12 @@ class JodaDateTimeAnalysisTest : BaseTest() { for (method in methods) { system.startTaintAnalysis(method) } + launch { + delay(20.seconds) + system.stop() + } system.awaitCompletion() + system.resume() val sinks = system.collectTaintResults() logger.info { "Vulnerabilities found: ${sinks.size}" } @@ -84,7 +92,6 @@ class JodaDateTimeAnalysisTest : BaseTest() { @Test fun `test NPE analysis`() = runBlocking { - // TODO: lacks timeout feature val clazz = cp.findClass() val methods = clazz.declaredMethods val ifdsContext = npeIfdsContext(cp, graph, defaultBannedPackagePrefixes) @@ -93,7 +100,12 @@ class JodaDateTimeAnalysisTest : BaseTest() { for (method in methods) { system.startNpeAnalysis(method) } + launch { + delay(20.seconds) + system.stop() + } system.awaitCompletion() + system.resume() val sinks = system.collectNpeResults() logger.info { "Vulnerabilities found: ${sinks.size}" } diff --git a/jacodb-ifds/actors/src/main/kotlin/Main.kt b/jacodb-ifds/actors/src/main/kotlin/Main.kt deleted file mode 100644 index 071390a02..000000000 --- a/jacodb-ifds/actors/src/main/kotlin/Main.kt +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -import org.jacodb.actors.api.Actor -import org.jacodb.actors.api.ActorContext -import org.jacodb.actors.api.ActorRef -import org.jacodb.actors.api.options.ChannelFactory.Companion.buffered -import org.jacodb.actors.api.options.SpawnOptions -import org.jacodb.actors.impl.routing.firstReadyRouter -import org.jacodb.actors.impl.systemOf -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay -import mu.KotlinLogging.logger -import java.util.concurrent.atomic.AtomicIntegerArray -import kotlin.system.measureTimeMillis - -const val CNT = 1_000 -const val SLEEP = 1L -const val PRODUCERS = 10 - -class Msg(val id: Int, val x: Int) - -sealed interface ConsumerMessage { - data class Ack(val rendezvous: Channel) : ConsumerMessage - data class Msg(val id: Int, val x: Int) : ConsumerMessage -} - -private var sums = AtomicIntegerArray(PRODUCERS) - -class Consumer( -) : Actor { - - override suspend fun receive(message: ConsumerMessage) { - delay(SLEEP) - when (message) { - is ConsumerMessage.Msg -> sums.addAndGet(message.id, message.x) - is ConsumerMessage.Ack -> {} - } - } -} - -context(ActorContext) -class Producer( - private val consumer: ActorRef, - private val iterations: Int, - private val sleep: Long, - private val id: Int, -) : Actor { - - override suspend fun receive(message: Unit) { - repeat(iterations) { - consumer.send(ConsumerMessage.Msg(id, 1)) - delay(sleep) - } - } -} - - -sealed interface RootMessage { - object Start : RootMessage - data class GetArray(val rendezvous: Channel) : RootMessage -} - -context(ActorContext) -class Root : Actor { - // private val consumers = spawn("consumer") { Consumer(PRODUCERS) } - private val consumers = spawn( - "consumer", - factory = firstReadyRouter(2) { Consumer() } - ) - - private val producers = List(PRODUCERS) { - spawn( - "producer#$it", - SpawnOptions.default.channelFactory(buffered(32768)) - ) { - Producer(consumers, iterations = CNT, sleep = SLEEP, it) - } - } - - override suspend fun receive(message: RootMessage) { - when (message) { - RootMessage.Start -> { - for (producer in producers) { - producer.send(Unit) - } - } - - is RootMessage.GetArray -> { - consumers.send(ConsumerMessage.Ack(message.rendezvous)) - } - } - } -} - -private val logger = logger("Main") - -suspend fun main() { - val system = systemOf("example", SpawnOptions.default, ::Root) - val ms = measureTimeMillis { - system.send(RootMessage.Start) - system.awaitCompletion() - logger.info { List(PRODUCERS) { sums.get(it) } } - } - logger.info { "Finished in $ms" } -} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt index 6bacda1dc..18a94f4a7 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt @@ -19,8 +19,6 @@ package org.jacodb.actors.api import org.jacodb.actors.api.signal.Signal interface Actor { - val flag: Boolean get() = true - suspend fun receive(message: M) suspend fun receive(signal: Signal) {} } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt index ccf5eafeb..c9e254b72 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt @@ -24,7 +24,7 @@ interface ActorContext : ActorSpawner { suspend fun ActorRef.send(message: TargetMessage) fun stop() - fun stopChild(name: String) + fun resume() val logger: KLogger } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Factory.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt similarity index 95% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Factory.kt rename to jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt index 4f252450f..35f1927f9 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Factory.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt @@ -16,6 +16,6 @@ package org.jacodb.actors.api -fun interface Factory { +fun interface ActorFactory { fun ActorContext.create(): Actor } \ No newline at end of file diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt index dd70da07a..696bc4486 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt @@ -16,6 +16,9 @@ package org.jacodb.actors.api -interface ActorRef { - val path: ActorPath +// Abstract class used instead of interface to support internal abstract functions +abstract class ActorRef( + val path: ActorPath, +) { + internal abstract suspend fun receive(message: M): Boolean } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt index bda2bdef3..e7d12af04 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt @@ -22,9 +22,12 @@ interface ActorSpawner { fun spawn( name: String, options: SpawnOptions = SpawnOptions.default, - factory: Factory, + actorFactory: ActorFactory, ): ActorRef fun child(name: String): ActorRef<*>? - fun children(): Collection> + fun children(): Map> + + fun stopChild(name: String) + fun resumeChild(name: String) } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt index e467e6e2b..7098638d5 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt @@ -26,4 +26,8 @@ interface ActorSystem { suspend fun ask(messageBuilder: (Channel) -> Message): R suspend fun awaitCompletion() + + suspend fun resume() + + fun stop() } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt index c4cb7252b..ac469510b 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt @@ -20,36 +20,42 @@ import mu.KLogger import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorSpawner -import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.impl.workers.ActorWorker import kotlin.coroutines.CoroutineContext internal class ActorContextImpl( private val spawner: ActorSpawner, - private val worker: ActorWorker, + val worker: ActorWorker, override val logger: KLogger, ) : ActorContext, ActorSpawner by spawner { override val self: ActorRef - get() = worker.self + get() = worker fun launch( coroutineContext: CoroutineContext, - factory: Factory, + actorFactory: ActorFactory, ) { - val actor = factory.run { create() } + val actor = actorFactory.run { create() } worker.launchLoop(coroutineContext, actor) } override suspend fun ActorRef.send(message: TargetMessage) { - worker.send(this as ActorRefImpl, message) + worker.send(this, message) } override fun stop() { - TODO("Not yet implemented") + worker.stop() + for ((name, _) in children()) { + stopChild(name) + } } - override fun stopChild(name: String) { - TODO("Not yet implemented") + override fun resume() { + worker.resume() + for ((name, _) in children()) { + resumeChild(name) + } } } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt index 0d4e96046..97e772d0c 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt @@ -21,8 +21,9 @@ import mu.KotlinLogging.logger import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorSpawner -import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.options.SpawnOptions +import org.jacodb.actors.impl.workers.ActorWorker import org.jacodb.actors.impl.workers.InternalActorWorker import org.jacodb.actors.impl.workers.UserActorWorker import org.jacodb.actors.impl.workers.WorkerFactory @@ -31,61 +32,61 @@ internal class ActorSpawnerImpl( private val self: ActorPath, private val system: ActorSystemImpl<*>, ) : ActorSpawner { - private val children = hashMapOf>() + private val children = hashMapOf>() override fun spawn( name: String, options: SpawnOptions, - factory: Factory, - ): ActorRefImpl = - spawnImpl(name, options, factory) { ref, channel, system -> + actorFactory: ActorFactory, + ): ActorWorker = + spawnImpl(name, options, actorFactory) { ref, channel, system -> UserActorWorker(ref, channel, system.scope, system.watcher) } internal fun spawnInternalActor( name: String, options: SpawnOptions, - factory: Factory, - ): ActorRefImpl = - spawnImpl(name, options, factory) { ref, channel, system -> + actorFactory: ActorFactory, + ): ActorWorker = + spawnImpl(name, options, actorFactory) { ref, channel, system -> InternalActorWorker(ref, channel, system.scope) } private fun spawnImpl( name: String, options: SpawnOptions, - factory: Factory, + actorFactory: ActorFactory, workerFactory: WorkerFactory, - ): ActorRefImpl { + ): ActorWorker { @Suppress("UNCHECKED_CAST") val channel = options.channelFactory.create() as Channel - val ref = createRef(name, channel) - - val spawner = ActorSpawnerImpl(ref.path, system) - - val worker = workerFactory(ref, channel, system) - val context = ActorContextImpl(spawner, worker, logger(ref.toString())) - context.launch(options.coroutineContext, factory) - - return ref - } - - private fun createRef( - name: String, - channel: Channel, - ): ActorRefImpl { if (children[name] != null) { error("$self already has $name child") } + val path = self / name - val ref = ActorRefImpl(path, channel) - children[name] = ref - return ref + + val spawner = ActorSpawnerImpl(path, system) + + val worker = workerFactory(path, channel, system) + val context = ActorContextImpl(spawner, worker, logger(path.toString())) + context.launch(options.coroutineContext, actorFactory) + children[name] = context + + return worker } override fun child(name: String): ActorRef<*>? = - children[name] + children[name]?.worker + + override fun children(): Map> = + children.mapValues { (_, v) -> v.worker } - override fun children(): Collection> = - children.values + override fun stopChild(name: String) { + children[name]?.stop() + } + + override fun resumeChild(name: String) { + children[name]?.resume() + } } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 05bb8074d..2784cae3a 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -16,12 +16,13 @@ package org.jacodb.actors.impl +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel import org.jacodb.actors.api.ActorSystem -import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.options.SpawnOptions import org.jacodb.actors.impl.actors.WatcherActor import org.jacodb.actors.impl.actors.WatcherMessage @@ -29,7 +30,7 @@ import org.jacodb.actors.impl.actors.WatcherMessage internal class ActorSystemImpl( override val name: String, options: SpawnOptions, - factory: Factory, + actorFactory: ActorFactory, ) : ActorSystem { private val path = root() / name @@ -37,39 +38,52 @@ internal class ActorSystemImpl( internal val scope = CoroutineScope(SupervisorJob()) - internal val watcher = spawner.spawnInternalActor("watcher", SpawnOptions.default, ::WatcherActor) + internal val watcher = spawner.spawnInternalActor(WATCHER_ACTOR_NAME, SpawnOptions.default, ::WatcherActor) - private val user = spawner.spawn("usr", options, factory) + private val user = spawner.spawn(USER_ACTOR_NAME, options, actorFactory) override suspend fun send(message: Message) { - watcher.send(WatcherMessage.OutOfSystemSend) - user.send(message) + watcher.receive(WatcherMessage.OutOfSystemSend) + user.receive(message) } override suspend fun ask(messageBuilder: (Channel) -> Message): R { - watcher.send(WatcherMessage.OutOfSystemSend) + watcher.receive(WatcherMessage.OutOfSystemSend) val channel = Channel(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) val ack = messageBuilder(channel) - user.send(ack) + user.receive(ack) val received = channel.receive() return received } override suspend fun awaitCompletion() { - val channel = Channel(capacity = 1, onBufferOverflow = BufferOverflow.SUSPEND) - watcher.send(WatcherMessage.AwaitTermination(channel)) - channel.receive() - watcher.send(WatcherMessage.Idle) + val ready = CompletableDeferred() + watcher.receive(WatcherMessage.AwaitTermination(ready)) + ready.await() + watcher.receive(WatcherMessage.Idle) + } + + override suspend fun resume() { + spawner.resumeChild(USER_ACTOR_NAME) + } + + override fun stop() { + spawner.stopChild(USER_ACTOR_NAME) + } + + companion object { + private const val USER_ACTOR_NAME = "usr" + private const val WATCHER_ACTOR_NAME = "watcher" } } fun systemOf( name: String, options: SpawnOptions = SpawnOptions.default, - factory: Factory, + actorFactory: ActorFactory, ): ActorSystem = ActorSystemImpl( name, options, - factory + actorFactory ) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt index 04be8b78f..dc534d6bb 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt @@ -16,11 +16,11 @@ package org.jacodb.actors.impl.actors +import kotlinx.coroutines.CompletableDeferred import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext -import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorStatus -import kotlinx.coroutines.channels.Channel context(ActorContext) @@ -28,7 +28,7 @@ internal class WatcherActor : Actor { private sealed interface Status { data object Idle : Status data class DetectingTermination( - val rendezvousChannel: Channel, + val computation: CompletableDeferred, ) : Status } @@ -39,7 +39,7 @@ internal class WatcherActor : Actor { var totalReceived: Long, ) - private val watchList = hashMapOf, Snapshot>() + private val watchList = hashMapOf() private val state = State( status = Status.Idle, terminatedActors = 0, @@ -58,35 +58,34 @@ internal class WatcherActor : Actor { } is WatcherMessage.AwaitTermination -> { - state.status = Status.DetectingTermination(message.rendezvous) + state.status = Status.DetectingTermination(message.computationFinished) } is WatcherMessage.Register -> { - state.terminatedActors++ - watchList[message.ref] = Snapshot(status = ActorStatus.IDLE, sent = 0, received = 0) + watchList[message.path] = Snapshot(status = ActorStatus.BUSY, sent = 0, received = 0) } is WatcherMessage.UpdateSnapshot -> { - updateSnapshot(message.ref, message.snapshot) + updateSnapshot(message.path, message.snapshot) } } val status = state.status if (status is Status.DetectingTermination) { - checkTermination(status.rendezvousChannel) + checkTermination(status.computation) } } - private suspend fun checkTermination(rendezvousOnTermination: Channel) { + private fun checkTermination(computationFinished: CompletableDeferred) { if (state.terminatedActors == watchList.size && state.totalSent == state.totalReceived) { logger.info { "Actors: ${state.terminatedActors}/${watchList.size}" } logger.info { "Messages: ${state.totalReceived}/${state.totalSent}" } logger.info { "Computation finished..." } - rendezvousOnTermination.send(Unit) + computationFinished.complete(Unit) } } - private fun updateSnapshot(ref: ActorRef<*>, newSnapshot: Snapshot) { - val currentSnapshot = watchList[ref] ?: error("$this can't find the current snapshot of $ref") + private fun updateSnapshot(path: ActorPath, newSnapshot: Snapshot) { + val currentSnapshot = watchList[path] ?: error("$this can't find the current snapshot of $path") if (newSnapshot.status == ActorStatus.BUSY && currentSnapshot.status == ActorStatus.IDLE) { state.terminatedActors-- @@ -96,6 +95,6 @@ internal class WatcherActor : Actor { } state.totalSent += newSnapshot.sent - currentSnapshot.sent state.totalReceived += newSnapshot.received - currentSnapshot.received - watchList[ref] = newSnapshot + watchList[path] = newSnapshot } } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt index 377c51207..2da52f778 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt @@ -16,9 +16,9 @@ package org.jacodb.actors.impl.actors -import org.jacodb.actors.api.ActorRef +import kotlinx.coroutines.CompletableDeferred +import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorStatus -import kotlinx.coroutines.channels.Channel internal data class Snapshot( val status: ActorStatus, @@ -31,17 +31,17 @@ internal sealed interface WatcherMessage { data object Idle : WatcherMessage data class Register( - val ref: ActorRef<*>, + val path: ActorPath, ) : WatcherMessage data object OutOfSystemSend : WatcherMessage data class UpdateSnapshot( - val ref: ActorRef<*>, + val path: ActorPath, val snapshot: Snapshot, ) : WatcherMessage data class AwaitTermination( - val rendezvous: Channel, + val computationFinished: CompletableDeferred, ) : WatcherMessage } \ No newline at end of file diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt index e95e7e893..37608b96e 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt @@ -16,30 +16,22 @@ package org.jacodb.actors.impl.routing -import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.options.SpawnOptions fun roundRobinRouter( size: Int = 8, routeeSpawnOptions: SpawnOptions = SpawnOptions.default, - routeeFactory: Factory, -) = Factory { + routeeFactory: ActorFactory, +) = ActorFactory { RoundRobinRouter(size, routeeSpawnOptions, routeeFactory) } -fun firstReadyRouter( - size: Int = 8, - routeeSpawnOptions: SpawnOptions = SpawnOptions.default, - routeeFactory: Factory, -) = Factory { - FirstReadyRouter(size, routeeSpawnOptions, routeeFactory) -} - fun randomRouter( size: Int = 8, routeeSpawnOptions: SpawnOptions = SpawnOptions.default, - routeeFactory: Factory, -) = Factory { + routeeFactory: ActorFactory, +) = ActorFactory { RandomRouter(size, routeeSpawnOptions, routeeFactory) } @@ -48,6 +40,6 @@ fun messageKeyRouter( routeeNameFactory: (Key) -> String = { it.toString() }, routeeSpawnOptions: SpawnOptions = SpawnOptions.default, routeeFactory: KeyRouteeFactory -) = Factory { +) = ActorFactory { MessageKeyRouter(keyExtractor, routeeNameFactory, routeeSpawnOptions, routeeFactory) } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt deleted file mode 100644 index 151012284..000000000 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/FirstReadyRouter.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.actors.impl.routing - -import org.jacodb.actors.api.Actor -import org.jacodb.actors.api.ActorContext -import org.jacodb.actors.api.Factory -import org.jacodb.actors.api.options.SpawnOptions - -context(ActorContext) -internal class FirstReadyRouter( - size: Int, - routeeSpawnOptions: SpawnOptions, - routeeFactory: Factory, -) : Actor { - override val flag: Boolean - get() = false - - private val channel = routeeSpawnOptions.channelFactory.create() - - init { - val options = routeeSpawnOptions.channel(channel) - repeat(size) { - spawn("$it", options, routeeFactory) - } - } - - override suspend fun receive(message: Message) { - channel.send(message) - } -} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt index 2fb2ccdab..b7ba31407 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt @@ -18,14 +18,14 @@ package org.jacodb.actors.impl.routing import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext -import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.options.SpawnOptions context(ActorContext) internal class RandomRouter( size: Int, routeeSpawnOptions: SpawnOptions, - routeeFactory: Factory + routeeFactory: ActorFactory ) : Actor { private val routees = List(size) { spawn("$it", routeeSpawnOptions, routeeFactory) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt index 3f21d2c11..212a78b17 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt @@ -18,14 +18,14 @@ package org.jacodb.actors.impl.routing import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext -import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.options.SpawnOptions context(ActorContext) internal class RoundRobinRouter( private val size: Int, routeeSpawnOptions: SpawnOptions, - routeeFactory: Factory + routeeFactory: ActorFactory ) : Actor { private val routees = List(size) { spawn("$it", routeeSpawnOptions, routeeFactory) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt index f00564a5b..853dd3274 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt @@ -18,25 +18,27 @@ package org.jacodb.actors.impl.workers import kotlinx.coroutines.channels.Channel import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef -import org.jacodb.actors.impl.ActorRefImpl import org.jacodb.actors.impl.ActorSystemImpl import kotlin.coroutines.CoroutineContext -internal typealias WorkerFactory = - (ActorRef, Channel, ActorSystemImpl<*>) -> ActorWorker +internal typealias WorkerFactory = + (ActorPath, Channel, ActorSystemImpl<*>) -> ActorWorker -internal interface ActorWorker { - val channel: Channel - val self: ActorRef - - fun launchLoop( +internal abstract class ActorWorker( + path: ActorPath +) : ActorRef(path) { + abstract fun launchLoop( coroutineContext: CoroutineContext, actor: Actor, ) - suspend fun send( - ref: ActorRefImpl, + abstract fun stop() + abstract fun resume() + + abstract suspend fun send( + destination: ActorRef, message: TargetMessage, ) } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt index ab0179815..f115e6534 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt @@ -20,15 +20,15 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef -import org.jacodb.actors.impl.ActorRefImpl import kotlin.coroutines.CoroutineContext internal class InternalActorWorker( - override val self: ActorRef, - override val channel: Channel, + path: ActorPath, + private val channel: Channel, private val scope: CoroutineScope, -) : ActorWorker { +) : ActorWorker(path) { override fun launchLoop( coroutineContext: CoroutineContext, actor: Actor, @@ -38,8 +38,19 @@ internal class InternalActorWorker( } } - override suspend fun send(ref: ActorRefImpl, message: TargetMessage) { - ref.send(message) + override fun stop() { + } + + override fun resume() { + } + + override suspend fun send(destination: ActorRef, message: TargetMessage) { + destination.receive(message) + } + + override suspend fun receive(message: Message): Boolean { + channel.send(message) + return true } private suspend fun loop( diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt index 327c84324..ccb81e7bd 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt @@ -17,59 +17,64 @@ package org.jacodb.actors.impl.workers import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.onClosed import kotlinx.coroutines.channels.onSuccess import kotlinx.coroutines.launch import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorStatus import org.jacodb.actors.api.signal.Signal -import org.jacodb.actors.impl.ActorRefImpl import org.jacodb.actors.impl.actors.Snapshot import org.jacodb.actors.impl.actors.WatcherMessage +import java.util.concurrent.atomic.AtomicBoolean import kotlin.coroutines.CoroutineContext internal class UserActorWorker( - override val self: ActorRef, - override val channel: Channel, + path: ActorPath, + private val channel: Channel, private val scope: CoroutineScope, - private val watcher: ActorRefImpl, -) : ActorWorker { + private val watcher: ActorRef, +) : ActorWorker(path) { private var received = 0 private var sent = 0 - private var status = ActorStatus.IDLE - private val job = Job() + private var status = ActorStatus.BUSY + private val working = AtomicBoolean(true) override fun launchLoop( coroutineContext: CoroutineContext, actor: Actor, ) { - scope.launch(job) { - sendInternal(watcher, WatcherMessage.Register(self)) + scope.launch { + sendInternal(watcher, WatcherMessage.Register(path)) actor.receive(Signal.Start) loop(actor) actor.receive(Signal.PostStop) } } - override suspend fun send(ref: ActorRefImpl, message: TargetMessage) { - sent++ - ref.send(message) + override suspend fun send(destination: ActorRef, message: TargetMessage) { + if (destination.receive(message)) { + sent++ + } + } + + override suspend fun receive(message: Message): Boolean { + channel.send(message) + return true } - private suspend fun sendInternal(ref: ActorRefImpl, message: TargetMessage) { - ref.send(message) + private suspend fun sendInternal(to: ActorRef, message: TargetMessage) { + to.receive(message) } private suspend fun loop( actor: Actor, ) { - var running = true - while (running) { + while (true) { var receiveResult = channel.tryReceive() if (receiveResult.isFailure) { processEmptyChannel() @@ -78,7 +83,6 @@ internal class UserActorWorker( receiveResult .onClosed { processEmptyChannel() - running = false } .onSuccess { message -> processMessage(actor, message) @@ -90,21 +94,34 @@ internal class UserActorWorker( actor: Actor, message: Message, ) { - if (actor.flag) { - received++ + updateReceived() + if (working.get()) { + actor.receive(message) } + } + + private suspend fun updateReceived() { + received++ + if (status == ActorStatus.IDLE) { status = ActorStatus.BUSY - watcher.send(WatcherMessage.UpdateSnapshot(self, Snapshot(status, sent, received))) + watcher.receive(WatcherMessage.UpdateSnapshot(path, Snapshot(status, sent, received))) } - actor.receive(message) } private suspend fun processEmptyChannel() { if (status == ActorStatus.BUSY) { status = ActorStatus.IDLE - val snapshot = WatcherMessage.UpdateSnapshot(self, Snapshot(status, sent, received)) - watcher.send(snapshot) + val snapshot = WatcherMessage.UpdateSnapshot(path, Snapshot(status, sent, received)) + watcher.receive(snapshot) } } + + override fun stop() { + working.set(false) + } + + override fun resume() { + working.set(true) + } } diff --git a/jacodb-ifds/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt b/jacodb-ifds/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt new file mode 100644 index 000000000..ccb2c4015 --- /dev/null +++ b/jacodb-ifds/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors + +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeoutOrNull +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.actors.impl.systemOf +import org.junit.jupiter.api.Test +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import kotlin.time.Duration.Companion.milliseconds + +class StoppingTest { + context(ActorContext) + class Repeater( + private val parent: ActorRef?, + depth: Int, + ) : Actor { + private val child: ActorRef? = + if (depth > 0) { + spawn("child") { Repeater(this@ActorContext.self, depth - 1) } + } else { + null + } + + override suspend fun receive(message: Int) { + delay(1) + child?.send(message + 1) + parent?.send(message + 1) + } + } + + @Test + fun testStops() = runBlocking { + val system = systemOf("test") { Repeater(null, 2) } + + system.send(0) + val job = launch { + system.awaitCompletion() + } + delay(50.milliseconds) + + assertTrue(job.isActive) + + system.stop() + + val result = withTimeoutOrNull(50.milliseconds) { + job.join() + } + assertNotNull(result) + } +} \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt index 9e824459e..5dee66af5 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt @@ -17,7 +17,7 @@ package org.jacodb.ifds import org.jacodb.actors.api.ActorRef -import org.jacodb.actors.api.Factory +import org.jacodb.actors.api.ActorFactory import org.jacodb.ifds.domain.Analyzer import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.domain.RunnerId @@ -29,5 +29,5 @@ interface IfdsContext { fun runnerIdByMessage(message: RunnerMessage): RunnerId fun getAnalyzer(chunk: Chunk, runnerId: RunnerId): Analyzer - fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId): Factory + fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId): ActorFactory } \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt index 8ede7c23b..3f81915a5 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt @@ -42,7 +42,7 @@ class ChunkManager( private val router = spawn( "runners", - factory = routerFactory + actorFactory = routerFactory ) override suspend fun receive(message: RunnerMessage) { diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt index bf741fc0b..489cf6191 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt @@ -39,7 +39,7 @@ class ProjectManager( keyExtractor = ifdsContext::chunkByMessage ) { chunk -> ChunkManager(ifdsContext, chunk, this@ActorContext.self) } - private val router = spawn("chunks", factory = routerFactory) + private val router = spawn("chunks", actorFactory = routerFactory) private val chunks = hashSetOf() diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt index c3e7b82e4..c81cb6709 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt @@ -19,9 +19,9 @@ package org.jacodb.ifds.actors import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef -import org.jacodb.actors.impl.routing.firstReadyRouter -import org.jacodb.ifds.domain.Chunk +import org.jacodb.actors.impl.routing.roundRobinRouter import org.jacodb.ifds.IfdsContext +import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.AnalyzerMessage import org.jacodb.ifds.messages.IndirectionMessage @@ -35,11 +35,11 @@ class Runner( private val chunk: Chunk, private val runnerId: RunnerId, ) : Actor { - private val routerFactory = firstReadyRouter(size = 8) { + private val routerFactory = roundRobinRouter(size = 8) { Worker(ifdsContext.getAnalyzer(chunk, runnerId), this@ActorContext.self) } - private val router = spawn("workers", factory = routerFactory) + private val router = spawn("workers", actorFactory = routerFactory) private val storage = spawn("storage") { RunnerStorage(this@ActorContext.self, runnerId) @@ -47,7 +47,7 @@ class Runner( private val indirectionHandler = spawn( "indirection", - factory = ifdsContext.indirectionHandlerFactory(this@ActorContext.self, runnerId) + actorFactory = ifdsContext.indirectionHandlerFactory(this@ActorContext.self, runnerId) ) override suspend fun receive(message: RunnerMessage) { From 534743af94ba94dc49fa4843109df004e98280ba Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Mon, 15 Apr 2024 10:47:48 +0300 Subject: [PATCH 13/64] [ifds] chore: removed generic fact parameter --- .../src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt | 2 +- .../ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt | 4 ++-- .../src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt | 6 +++--- .../main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt | 6 +++--- .../ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt | 6 ++++-- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt index a7a45efcc..ad2123b82 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt @@ -34,7 +34,7 @@ class JcIfdsContext( private val bannedPackagePrefixes: List, private val chunkStrategy: ChunkResolver, private val flowFunctionFactory: (RunnerId) -> FlowFunction, -) : IfdsContext { +) : IfdsContext { override fun chunkByMessage(message: RunnerMessage): Chunk = chunkStrategy.chunkByMessage(message) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt index 5dee66af5..f60991472 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt @@ -24,10 +24,10 @@ import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.IndirectionMessage -interface IfdsContext { +interface IfdsContext { fun chunkByMessage(message: RunnerMessage): Chunk fun runnerIdByMessage(message: RunnerMessage): RunnerId - fun getAnalyzer(chunk: Chunk, runnerId: RunnerId): Analyzer + fun getAnalyzer(chunk: Chunk, runnerId: RunnerId): Analyzer fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId): ActorFactory } \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt index 3f81915a5..14f4ca281 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt @@ -28,8 +28,8 @@ import org.jacodb.ifds.messages.NewChunk import org.jacodb.ifds.messages.RunnerMessage context(ActorContext) -class ChunkManager( - private val ifdsContext: IfdsContext, +class ChunkManager( + private val ifdsContext: IfdsContext, private val chunk: Chunk, private val parent: ActorRef, ) : Actor { @@ -37,7 +37,7 @@ class ChunkManager( private val routerFactory = messageKeyRouter( ifdsContext::runnerIdByMessage ) { runnerId -> - Runner(this@ActorContext.self, ifdsContext, chunk, runnerId) + Runner(this@ActorContext.self, ifdsContext, chunk, runnerId) } private val router = spawn( diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt index 489cf6191..8e86c3a69 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt @@ -32,8 +32,8 @@ import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.IfdsResult context(ActorContext) -class ProjectManager( - private val ifdsContext: IfdsContext, +class ProjectManager( + private val ifdsContext: IfdsContext, ) : Actor { private val routerFactory = messageKeyRouter( keyExtractor = ifdsContext::chunkByMessage @@ -64,7 +64,7 @@ class ProjectManager( is CollectAll -> { val results = hashMapOf>() for (chunk in chunks) { - val channel = Channel>>() + val channel = Channel>>() val msg = ObtainData(chunk, message.runnerId, channel) router.send(msg) val data = channel.receive() diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt index c81cb6709..c642e63ee 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt @@ -21,6 +21,7 @@ import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.actors.impl.routing.roundRobinRouter import org.jacodb.ifds.IfdsContext +import org.jacodb.ifds.domain.Analyzer import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.AnalyzerMessage @@ -31,12 +32,13 @@ import org.jacodb.ifds.messages.StorageMessage context(ActorContext) class Runner( private val parent: ActorRef, - private val ifdsContext: IfdsContext, + private val ifdsContext: IfdsContext, private val chunk: Chunk, private val runnerId: RunnerId, ) : Actor { private val routerFactory = roundRobinRouter(size = 8) { - Worker(ifdsContext.getAnalyzer(chunk, runnerId), this@ActorContext.self) + @Suppress("UNCHECKED_CAST") + Worker(ifdsContext.getAnalyzer(chunk, runnerId) as Analyzer, this@ActorContext.self) } private val router = spawn("workers", actorFactory = routerFactory) From 72cffcbb4e2afc35a6ccbaaa0687b72edb7b5fec Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Mon, 15 Apr 2024 15:49:06 +0300 Subject: [PATCH 14/64] [ifds] fix: IRTest and Type Tests --- jacodb-core/build.gradle.kts | 7 +++++ .../org/jacodb/impl/cfg/RawInstListBuilder.kt | 27 +++++++------------ .../org/jacodb/testing/types/TypesTest.kt | 7 +---- .../kotlin/org/jacodb/testing/Example.kt | 23 ++++++++++++++++ 4 files changed, 40 insertions(+), 24 deletions(-) create mode 100644 jacodb-core/src/testFixtures/kotlin/org/jacodb/testing/Example.kt diff --git a/jacodb-core/build.gradle.kts b/jacodb-core/build.gradle.kts index b800d11c4..187ba76c5 100644 --- a/jacodb-core/build.gradle.kts +++ b/jacodb-core/build.gradle.kts @@ -1,3 +1,4 @@ +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jooq.codegen.GenerationTool import org.jooq.meta.jaxb.* import org.jooq.meta.jaxb.Configuration @@ -94,4 +95,10 @@ tasks { expand("version" to project.version) } } + + compileTestFixturesKotlin { + compilerOptions { + languageVersion.set(KotlinVersion.KOTLIN_1_7) + } + } } diff --git a/jacodb-core/src/main/kotlin/org/jacodb/impl/cfg/RawInstListBuilder.kt b/jacodb-core/src/main/kotlin/org/jacodb/impl/cfg/RawInstListBuilder.kt index 35e6d7aab..9ce992629 100644 --- a/jacodb-core/src/main/kotlin/org/jacodb/impl/cfg/RawInstListBuilder.kt +++ b/jacodb-core/src/main/kotlin/org/jacodb/impl/cfg/RawInstListBuilder.kt @@ -20,7 +20,6 @@ import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList import org.jacodb.api.JcMethod -import org.jacodb.api.JcParameter import org.jacodb.api.PredefinedPrimitives import org.jacodb.api.TypeName import org.jacodb.api.cfg.BsmArg @@ -123,7 +122,6 @@ import org.objectweb.asm.tree.JumpInsnNode import org.objectweb.asm.tree.LabelNode import org.objectweb.asm.tree.LdcInsnNode import org.objectweb.asm.tree.LineNumberNode -import org.objectweb.asm.tree.LocalVariableNode import org.objectweb.asm.tree.LookupSwitchInsnNode import org.objectweb.asm.tree.MethodInsnNode import org.objectweb.asm.tree.MethodNode @@ -684,28 +682,21 @@ class RawInstListBuilder( var localsRealSize = 0 argCounter = 0 - var staticInc = 0 if (!method.isStatic) { locals = locals.add(argCounter, thisRef()) localsRealSize = argCounter + 1 argCounter++ - staticInc = 1 - } - val variables = methodNode.localVariables.orEmpty().sortedBy(LocalVariableNode::index) - - fun getName(parameter: JcParameter): String? { - val idx = parameter.index + staticInc - return if (idx < variables.size) { - variables[idx].name - } else { - parameter.name - } } + val variables = methodNode.localVariables.orEmpty() for (parameter in method.parameters) { - val argument = JcRawArgument.of(parameter.index, getName(parameter), parameter.type) - + val name = variables.firstOrNull { it.index == argCounter }?.name ?: parameter.name + val argument = JcRawArgument.of( + parameter.index, + name, + parameter.type + ) locals = locals.add(argCounter, argument) localsRealSize = argCounter + 1 @@ -1122,12 +1113,12 @@ class RawInstListBuilder( .firstOrNull { it.index == variable && curLabel.isBetween(it.start, it.end) } val isArg = if (actualLocalFromDebugInfo == null) { - variable < argCounter + false } else { actualLocalFromDebugInfo.start == methodNode.instructions.firstOrNull { it is LabelNode } } - if (variable < argCounter && isArg) { + if (isArg) { val value = frames.values.firstOrNull { val value = it.findLocal(variable) value != null && (value is JcRawArgument || value is JcRawThis) diff --git a/jacodb-core/src/test/kotlin/org/jacodb/testing/types/TypesTest.kt b/jacodb-core/src/test/kotlin/org/jacodb/testing/types/TypesTest.kt index 895a7f6a4..058a3de79 100644 --- a/jacodb-core/src/test/kotlin/org/jacodb/testing/types/TypesTest.kt +++ b/jacodb-core/src/test/kotlin/org/jacodb/testing/types/TypesTest.kt @@ -27,6 +27,7 @@ import org.jacodb.api.ext.toType import org.jacodb.impl.types.JcClassTypeImpl import org.jacodb.impl.types.signature.JvmClassRefType import org.jacodb.impl.types.substition.JcSubstitutorImpl +import org.jacodb.testing.Example import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Test import java.io.InputStream @@ -66,12 +67,6 @@ class TypesTest : BaseTypesTest() { @Test fun `parameters test`() { - class Example { - fun f(notNullable: String, nullable: String?): Int { - return 0 - } - } - val type = findType() val actualParameters = type.declaredMethods.single { it.name == "f" }.parameters assertEquals(listOf("notNullable", "nullable"), actualParameters.map { it.name }) diff --git a/jacodb-core/src/testFixtures/kotlin/org/jacodb/testing/Example.kt b/jacodb-core/src/testFixtures/kotlin/org/jacodb/testing/Example.kt new file mode 100644 index 000000000..f6cf4c7d0 --- /dev/null +++ b/jacodb-core/src/testFixtures/kotlin/org/jacodb/testing/Example.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.testing + +class Example { + fun f(notNullable: String, nullable: String?): Int { + return 0 + } +} \ No newline at end of file From d4c5e3582c8511c78e0690101d567ab8dfdebd33 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Mon, 15 Apr 2024 15:57:00 +0300 Subject: [PATCH 15/64] [ifds] fix: build-and-test.yml single run --- .github/workflows/build-and-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index cb79cc5a5..be7d29c18 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -2,6 +2,8 @@ name: Build and run tests on: push: + branches: + - develop pull_request: branches: - develop From 6983a9555faa75b782605cd19199190ebe03e877 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Mon, 15 Apr 2024 16:03:05 +0300 Subject: [PATCH 16/64] [ifds] fix: build-and-test.yml workflow_dispatch --- .github/workflows/build-and-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index be7d29c18..c3802bc00 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -7,6 +7,7 @@ on: pull_request: branches: - develop + workflow_dispatch: permissions: contents: read From 1ddcba94c23a282b349b40d46f288c016c713208 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Mon, 15 Apr 2024 16:06:52 +0300 Subject: [PATCH 17/64] [ifds] fix: remove foojay --- settings.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 5df0a59fc..2f7632de4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,7 +3,6 @@ rootProject.name = "jacodb" plugins { `gradle-enterprise` id("org.danilopianini.gradle-pre-commit-git-hooks") version "1.1.11" - id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0" } gradleEnterprise { From 75fb2da5db6721001fdf24cf05f82b99ee1eb91f Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 16 Apr 2024 12:24:54 +0300 Subject: [PATCH 18/64] [ifds] chore: `Channel` to `CompletableDeferred` --- .../kotlin/org/jacodb/actors/api/ActorSystem.kt | 4 ++-- .../org/jacodb/actors/impl/ActorSystemImpl.kt | 14 ++++++-------- .../org/jacodb/ifds/actors/ProjectManager.kt | 2 +- .../org/jacodb/ifds/messages/ProjectMessages.kt | 4 ++-- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt index 7098638d5..f226b62d3 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt @@ -16,14 +16,14 @@ package org.jacodb.actors.api -import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.CompletableDeferred interface ActorSystem { val name: String suspend fun send(message: Message) - suspend fun ask(messageBuilder: (Channel) -> Message): R + suspend fun ask(messageBuilder: (CompletableDeferred) -> Message): R suspend fun awaitCompletion() diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 2784cae3a..8e45dc55a 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -19,10 +19,8 @@ package org.jacodb.actors.impl import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.channels.BufferOverflow -import kotlinx.coroutines.channels.Channel -import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.api.ActorFactory +import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.api.options.SpawnOptions import org.jacodb.actors.impl.actors.WatcherActor import org.jacodb.actors.impl.actors.WatcherMessage @@ -47,13 +45,13 @@ internal class ActorSystemImpl( user.receive(message) } - override suspend fun ask(messageBuilder: (Channel) -> Message): R { + override suspend fun ask(messageBuilder: (CompletableDeferred) -> Message): R { watcher.receive(WatcherMessage.OutOfSystemSend) - val channel = Channel(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) - val ack = messageBuilder(channel) + val deferred = CompletableDeferred() + val ack = messageBuilder(deferred) user.receive(ack) - val received = channel.receive() - return received + val answer = deferred.await() + return answer } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt index 8e86c3a69..bb2599bd9 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt @@ -70,7 +70,7 @@ class ProjectManager( val data = channel.receive() results[chunk] = data } - message.channel.send(results) + message.result.complete(results) } } } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt index 89cc51cc6..96eb859f1 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt @@ -16,7 +16,7 @@ package org.jacodb.ifds.messages -import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.CompletableDeferred import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.result.IfdsComputationData @@ -29,5 +29,5 @@ data class NewChunk( data class CollectAll( val runnerId: RunnerId, - val channel: Channel>> + val result: CompletableDeferred>> ) : ProjectMessage \ No newline at end of file From 6b5a78c3b6165fde30772acddc56d8c825a1e5cd Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Mon, 22 Apr 2024 14:55:52 +0300 Subject: [PATCH 19/64] [ifds] chore: cleanup/format --- .../kotlin/org/jacodb/ifds/ChunkStrategies.kt | 19 ++++++++++--------- .../kotlin/org/jacodb/ifds/taint/Context.kt | 15 ++++++++------- .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 1 - .../jacodb/actors/impl/ActorContextImpl.kt | 2 +- .../org/jacodb/actors/impl/ActorPathImpl.kt | 2 +- .../jacodb/actors/impl/ActorSpawnerImpl.kt | 3 ++- .../org/jacodb/actors/impl/ActorSystemImpl.kt | 1 - .../jacodb/actors/impl/workers/ActorWorker.kt | 2 +- .../impl/workers/InternalActorWorker.kt | 1 + jacodb-ifds/ifds/build.gradle.kts | 1 - .../kotlin/org/jacodb/ifds/IfdsContext.kt | 2 +- .../org/jacodb/ifds/actors/ChunkManager.kt | 3 ++- .../org/jacodb/ifds/actors/ProjectManager.kt | 1 + .../kotlin/org/jacodb/ifds/actors/Runner.kt | 3 ++- .../org/jacodb/ifds/actors/RunnerStorage.kt | 17 +++++++---------- .../kotlin/org/jacodb/ifds/actors/Worker.kt | 2 +- .../kotlin/org/jacodb/ifds/domain/Analyzer.kt | 1 + .../kotlin/org/jacodb/ifds/domain/Edge.kt | 2 +- .../org/jacodb/ifds/domain/FlowFunction.kt | 1 + .../jacodb/ifds/messages/ProjectMessages.kt | 2 +- .../org/jacodb/ifds/result/IfdsResult.kt | 2 +- .../kotlin/org/jacodb/ifds/result/Merging.kt | 2 +- .../org/jacodb/ifds/result/TraceGraph.kt | 2 +- 23 files changed, 45 insertions(+), 42 deletions(-) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt index b73b97b07..1b2afe658 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt @@ -22,6 +22,7 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.packageName import org.jacodb.ifds.domain.Chunk +// TODO: consider 'SingletonChunk' data object SingleChunk : Chunk val SingleChunkStrategy = ChunkStrategy { @@ -32,21 +33,21 @@ data class MethodChunk( val method: JcMethod, ) : Chunk -val MethodChunkStrategy = ChunkStrategy { - MethodChunk(it.location.method) +val MethodChunkStrategy = ChunkStrategy { stmt -> + MethodChunk(stmt.location.method) } data class ClassChunk( val method: JcClassOrInterface, ) : Chunk -val ClassChunkStrategy = ChunkStrategy { - val jcClass = it.location.method.enclosingClass +val ClassChunkStrategy = ChunkStrategy { stmt -> + val jcClass = stmt.location.method.enclosingClass ClassChunk(jcClass) } -val ClassWithNestedChunkStrategy = ChunkStrategy { - val jClass = generateSequence(it.location.method.enclosingClass) { it.outerClass } +val ClassWithNestedChunkStrategy = ChunkStrategy { stmt -> + val jClass = generateSequence(stmt.location.method.enclosingClass) { it.outerClass } .last() ClassChunk(jClass) } @@ -55,6 +56,6 @@ data class PackageChunk( val packageName: String, ) : Chunk -val PackageChunkStrategy = ChunkStrategy { - PackageChunk(it.location.method.enclosingClass.packageName) -} \ No newline at end of file +val PackageChunkStrategy = ChunkStrategy { stmt -> + PackageChunk(stmt.location.method.enclosingClass.packageName) +} diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt index 506672b98..01a86e090 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -18,6 +18,7 @@ package org.jacodb.ifds.taint import org.jacodb.analysis.taint.BackwardTaintAnalyzer import org.jacodb.analysis.taint.EdgeForOtherRunner +import org.jacodb.analysis.taint.NewSummaryEdge import org.jacodb.analysis.taint.NewVulnerability import org.jacodb.analysis.taint.TaintAnalyzer import org.jacodb.analysis.taint.TaintDomainFact @@ -30,10 +31,10 @@ import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.NewResult -import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.toEdge +import org.jacodb.ifds.messages.NewEdge as IfdsNewEdge +import org.jacodb.ifds.messages.NewResult as IfdsNewResult +import org.jacodb.ifds.messages.NewSummaryEdge as IfdsNewSummaryEdge private fun complementRunner(type: RunnerId): RunnerId = when (type) { @@ -69,7 +70,7 @@ fun taintIfdsContext( is EdgeForOtherRunner -> { if (useBackwardRunner) { val edgeForOtherRunner = - NewEdge( + IfdsNewEdge( complementRunner(runnerId), event.edge.toEdge(), Reason.FromOtherRunner(edge, runnerId) @@ -78,13 +79,13 @@ fun taintIfdsContext( } } - is org.jacodb.analysis.taint.NewSummaryEdge -> { - val summaryEdge = NewSummaryEdge(runnerId, event.edge.toEdge()) + is NewSummaryEdge -> { + val summaryEdge = IfdsNewSummaryEdge(runnerId, event.edge.toEdge()) add(summaryEdge) } is NewVulnerability -> { - val result = NewResult(runnerId, TaintVulnerability(event.vulnerability)) + val result = IfdsNewResult(runnerId, TaintVulnerability(event.vulnerability)) add(result) } } diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index da36ed237..b19c986a3 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -91,7 +91,6 @@ class IfdsSqlTest : BaseAnalysisTest() { system.collectTaintResults() } - @ParameterizedTest @MethodSource("provideClassesForJuliet89") fun `test on Juliet's CWE 89`(className: String) { diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt index ac469510b..f57e3eed4 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt @@ -18,9 +18,9 @@ package org.jacodb.actors.impl import mu.KLogger import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorSpawner -import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.impl.workers.ActorWorker import kotlin.coroutines.CoroutineContext diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt index 1f03ce0c8..c14cf2934 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt @@ -25,7 +25,7 @@ internal data class ActorPathImpl( ActorPathImpl(path + name) override fun toString(): String = - path.joinToString(separator = "/", prefix = "/") + path.joinToString(prefix = "/", separator = "/") companion object { val emptyPath = ActorPathImpl(emptyList()) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt index 97e772d0c..2dbd31d4c 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt @@ -18,10 +18,10 @@ package org.jacodb.actors.impl import kotlinx.coroutines.channels.Channel import mu.KotlinLogging.logger +import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorSpawner -import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.options.SpawnOptions import org.jacodb.actors.impl.workers.ActorWorker import org.jacodb.actors.impl.workers.InternalActorWorker @@ -32,6 +32,7 @@ internal class ActorSpawnerImpl( private val self: ActorPath, private val system: ActorSystemImpl<*>, ) : ActorSpawner { + private val children = hashMapOf>() override fun spawn( diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 8e45dc55a..be8afecd9 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -54,7 +54,6 @@ internal class ActorSystemImpl( return answer } - override suspend fun awaitCompletion() { val ready = CompletableDeferred() watcher.receive(WatcherMessage.AwaitTermination(ready)) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt index 853dd3274..0b9d9f845 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt @@ -27,7 +27,7 @@ internal typealias WorkerFactory = (ActorPath, Channel, ActorSystemImpl<*>) -> ActorWorker internal abstract class ActorWorker( - path: ActorPath + path: ActorPath, ) : ActorRef(path) { abstract fun launchLoop( coroutineContext: CoroutineContext, diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt index f115e6534..286997203 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt @@ -29,6 +29,7 @@ internal class InternalActorWorker( private val channel: Channel, private val scope: CoroutineScope, ) : ActorWorker(path) { + override fun launchLoop( coroutineContext: CoroutineContext, actor: Actor, diff --git a/jacodb-ifds/ifds/build.gradle.kts b/jacodb-ifds/ifds/build.gradle.kts index 8d2f7d540..586d344a5 100644 --- a/jacodb-ifds/ifds/build.gradle.kts +++ b/jacodb-ifds/ifds/build.gradle.kts @@ -3,7 +3,6 @@ dependencies { implementation(Libs.slf4j_simple) implementation(Libs.kotlinx_coroutines_core) - // ifds implementation(project(":jacodb-ifds:actors")) testImplementation("org.jetbrains.kotlin:kotlin-test") diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt index f60991472..55d448c44 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt @@ -30,4 +30,4 @@ interface IfdsContext { fun getAnalyzer(chunk: Chunk, runnerId: RunnerId): Analyzer fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId): ActorFactory -} \ No newline at end of file +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt index 14f4ca281..a652683f5 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt @@ -59,7 +59,8 @@ class ChunkManager( parent.send(NewChunk(chunk)) } Signal.PostStop -> { - + // TODO: explain why we do nothing here + // do nothing } } } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt index bb2599bd9..db7a17fdb 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt @@ -35,6 +35,7 @@ context(ActorContext) class ProjectManager( private val ifdsContext: IfdsContext, ) : Actor { + private val routerFactory = messageKeyRouter( keyExtractor = ifdsContext::chunkByMessage ) { chunk -> ChunkManager(ifdsContext, chunk, this@ActorContext.self) } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt index c642e63ee..42fa8c206 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt @@ -38,7 +38,8 @@ class Runner( ) : Actor { private val routerFactory = roundRobinRouter(size = 8) { @Suppress("UNCHECKED_CAST") - Worker(ifdsContext.getAnalyzer(chunk, runnerId) as Analyzer, this@ActorContext.self) + val analyzer = ifdsContext.getAnalyzer(chunk, runnerId) as Analyzer + Worker(analyzer, this@ActorContext.self) } private val router = spawn("workers", actorFactory = routerFactory) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt index 92ba4e1d1..775d4b97d 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt @@ -23,7 +23,6 @@ import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.EdgeMessage import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.messages.NewResult @@ -31,6 +30,7 @@ import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.messages.NotificationOnEnd import org.jacodb.ifds.messages.NotificationOnStart import org.jacodb.ifds.messages.ObtainData +import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.StorageMessage import org.jacodb.ifds.messages.SubscriptionOnEnd import org.jacodb.ifds.messages.SubscriptionOnStart @@ -66,6 +66,7 @@ class RunnerStorage( is NewEdge<*, *> -> { @Suppress("UNCHECKED_CAST") message as NewEdge + val edge = message.edge reasons @@ -83,6 +84,7 @@ class RunnerStorage( message as NewSummaryEdge val edge = message.edge + if (summaryEdges.add(edge)) { summaryEdgesByStart .computeIfAbsent(edge.from) { hashSetOf() } @@ -147,7 +149,7 @@ class RunnerStorage( vertex: Vertex, subscriptionData: SubscriptionData, ) { - val summaries = summaryEdgesByStart.getOrDefault(vertex, emptySet()) + val summaries = summaryEdgesByStart[vertex].orEmpty() for (summaryEdge in summaries) { val notification = NotificationOnStart( subscriptionData.subscriber, @@ -163,7 +165,7 @@ class RunnerStorage( vertex: Vertex, subscriptionData: SubscriptionData, ) { - val summaries = summaryEdgesByEnd.getOrDefault(vertex, emptySet()) + val summaries = summaryEdgesByEnd[vertex].orEmpty() for (summaryEdge in summaries) { val notification = NotificationOnEnd( subscriptionData.subscriber, @@ -175,11 +177,8 @@ class RunnerStorage( } } - private suspend fun sendStartNotifications(edge: Edge) { - val currentEdgeStartSubscribers = startSubscribers - .getOrDefault(edge.from, emptySet()) - + val currentEdgeStartSubscribers = startSubscribers[edge.from].orEmpty() for ((data, subscriber) in currentEdgeStartSubscribers) { val notification = NotificationOnStart( subscriber, @@ -192,9 +191,7 @@ class RunnerStorage( } private suspend fun sendEndNotifications(edge: Edge) { - val currentEdgeEndSubscribers = endSubscribers - .getOrDefault(edge.to, emptySet()) - + val currentEdgeEndSubscribers = endSubscribers[edge.to].orEmpty() for ((data, subscriber) in currentEdgeEndSubscribers) { val notification = NotificationOnEnd( subscriber, diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt index 5f1f0b272..6a289831a 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt @@ -35,4 +35,4 @@ class Worker( parent.send(newMessage) } } -} \ No newline at end of file +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt index 066207f2a..1e530ece1 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt @@ -20,5 +20,6 @@ import org.jacodb.ifds.messages.AnalyzerMessage import org.jacodb.ifds.messages.RunnerMessage interface Analyzer { + // TODO: consider 'handle' fun step(message: AnalyzerMessage): Collection } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt index a8320122b..78ae745e7 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt @@ -19,4 +19,4 @@ package org.jacodb.ifds.domain data class Edge( val from: Vertex, val to: Vertex -) \ No newline at end of file +) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt index d176a9425..f292ebbbf 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt @@ -16,6 +16,7 @@ package org.jacodb.ifds.domain +// TODO: consider 'FlowFunctions' (plural) interface FlowFunction { fun FlowScope.sequent( next: Stmt, diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt index 96eb859f1..22e475699 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt @@ -30,4 +30,4 @@ data class NewChunk( data class CollectAll( val runnerId: RunnerId, val result: CompletableDeferred>> -) : ProjectMessage \ No newline at end of file +) : ProjectMessage diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt index d0b3a71e7..844c07d22 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt @@ -20,4 +20,4 @@ import org.jacodb.ifds.domain.Vertex interface IfdsResult { val vertex: Vertex -} \ No newline at end of file +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt index 6e2374651..905ee7b13 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt @@ -49,4 +49,4 @@ fun > mergeIfdsResults( results ) return mergedData -} \ No newline at end of file +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt index 19dbdcbb9..c9572ac50 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt @@ -27,4 +27,4 @@ interface TraceGraph { * Returns all traces from [sources] to [sink]. */ fun getAllTraces(): Sequence>> -} \ No newline at end of file +} From 0ebc6ee35730689722c41df2bce873f68f257be7 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Mon, 22 Apr 2024 14:16:06 +0300 Subject: [PATCH 20/64] [ifds] fix: use kotlin("test") --- jacodb-ifds/actors/build.gradle.kts | 2 +- jacodb-ifds/ifds/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jacodb-ifds/actors/build.gradle.kts b/jacodb-ifds/actors/build.gradle.kts index 39fefca11..2386bc53c 100644 --- a/jacodb-ifds/actors/build.gradle.kts +++ b/jacodb-ifds/actors/build.gradle.kts @@ -3,5 +3,5 @@ dependencies { implementation(Libs.slf4j_simple) implementation(Libs.kotlinx_coroutines_core) - testImplementation("org.jetbrains.kotlin:kotlin-test") + testImplementation(kotlin("test")) } diff --git a/jacodb-ifds/ifds/build.gradle.kts b/jacodb-ifds/ifds/build.gradle.kts index 586d344a5..da3056149 100644 --- a/jacodb-ifds/ifds/build.gradle.kts +++ b/jacodb-ifds/ifds/build.gradle.kts @@ -5,5 +5,5 @@ dependencies { implementation(project(":jacodb-ifds:actors")) - testImplementation("org.jetbrains.kotlin:kotlin-test") + testImplementation(kotlin("test")) } From 5eb5da31baf5413a7276f226345abc43f5d9644f Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Mon, 22 Apr 2024 14:20:52 +0300 Subject: [PATCH 21/64] [ifds] chore: import alias --- .../src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index 61d36013f..f92668638 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -31,6 +31,7 @@ import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.mergeIfdsResults import org.jacodb.impl.features.usagesExt +import org.jacodb.analysis.taint.TaintVulnerability as JcTaintVulnerability suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath @@ -46,7 +47,7 @@ suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { } } -suspend fun ActorSystem.collectTaintResults(): List = +suspend fun ActorSystem.collectTaintResults(): List = collectTaintComputationData() .results .mapTo(mutableListOf()) { it.vulnerability } From f30cff3ea16849f26ac22613d6ccc4783d9d557d Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Mon, 22 Apr 2024 14:41:23 +0300 Subject: [PATCH 22/64] [ifds] chore: add todo about renaming systemOf to system --- .../src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index be8afecd9..4851b7087 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -75,6 +75,7 @@ internal class ActorSystemImpl( } } +// TODO: consider just 'system', because 'Of' implies a vararg, which is not the case here fun systemOf( name: String, options: SpawnOptions = SpawnOptions.default, From 97ee4fb9e9eb2523fe88b85b8643b8693897dd12 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Mon, 22 Apr 2024 15:32:40 +0300 Subject: [PATCH 23/64] [ifds] fix: use TaintAnalyzer --- .../src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index f92668638..70aa6c7d4 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -18,7 +18,7 @@ package org.jacodb.ifds.taint import org.jacodb.actors.api.ActorSystem import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.npe.NpeAnalyzer +import org.jacodb.analysis.taint.TaintAnalyzer import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst @@ -36,7 +36,7 @@ import org.jacodb.analysis.taint.TaintVulnerability as JcTaintVulnerability suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val taintAnalyzer = NpeAnalyzer(graph) + val taintAnalyzer = TaintAnalyzer(graph) for (fact in taintAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { From 8c068afbb32a07d7fbea5656718507c5f6a4e454 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Mon, 22 Apr 2024 15:50:29 +0300 Subject: [PATCH 24/64] [ifds] chore: format --- .../src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt | 2 +- .../main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt | 1 - .../kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt | 2 +- .../main/kotlin/org/jacodb/actors/impl/routing/Builders.kt | 2 +- .../kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt | 2 +- .../kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt | 2 +- .../kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt | 4 ++-- .../kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt | 1 - .../ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt | 1 - .../ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt | 4 ++-- .../src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt | 3 ++- .../ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt | 2 +- .../ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt | 2 +- .../ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt | 2 +- .../ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt | 2 +- .../ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt | 4 ++-- .../main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt | 2 +- .../main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt | 4 ++-- .../main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt | 1 - 19 files changed, 20 insertions(+), 23 deletions(-) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt index c14cf2934..3e28bb646 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt @@ -19,7 +19,7 @@ package org.jacodb.actors.impl import org.jacodb.actors.api.ActorPath internal data class ActorPathImpl( - private val path: List + private val path: List, ) : ActorPath { override fun div(name: String): ActorPath = ActorPathImpl(path + name) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt index dc534d6bb..462e2ff75 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt @@ -22,7 +22,6 @@ import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorStatus - context(ActorContext) internal class WatcherActor : Actor { private sealed interface Status { diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt index 2da52f778..cabb8d775 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt @@ -44,4 +44,4 @@ internal sealed interface WatcherMessage { data class AwaitTermination( val computationFinished: CompletableDeferred, ) : WatcherMessage -} \ No newline at end of file +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt index 37608b96e..63be407a3 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt @@ -39,7 +39,7 @@ fun messageKeyRouter( keyExtractor: (Message) -> Key, routeeNameFactory: (Key) -> String = { it.toString() }, routeeSpawnOptions: SpawnOptions = SpawnOptions.default, - routeeFactory: KeyRouteeFactory + routeeFactory: KeyRouteeFactory, ) = ActorFactory { MessageKeyRouter(keyExtractor, routeeNameFactory, routeeSpawnOptions, routeeFactory) } diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt index 50d24b92d..02416aea9 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt @@ -17,8 +17,8 @@ package org.jacodb.actors.impl.routing import org.jacodb.actors.api.Actor -import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.options.SpawnOptions internal typealias KeyRouteeFactory = ActorContext.(Key) -> Actor diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt index b7ba31407..4bf00b0b8 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt @@ -25,7 +25,7 @@ context(ActorContext) internal class RandomRouter( size: Int, routeeSpawnOptions: SpawnOptions, - routeeFactory: ActorFactory + routeeFactory: ActorFactory, ) : Actor { private val routees = List(size) { spawn("$it", routeeSpawnOptions, routeeFactory) diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt index 212a78b17..3f6777138 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt @@ -25,7 +25,7 @@ context(ActorContext) internal class RoundRobinRouter( private val size: Int, routeeSpawnOptions: SpawnOptions, - routeeFactory: ActorFactory + routeeFactory: ActorFactory, ) : Actor { private val routees = List(size) { spawn("$it", routeeSpawnOptions, routeeFactory) @@ -39,4 +39,4 @@ internal class RoundRobinRouter( counter = 0 } } -} \ No newline at end of file +} diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt index ccb81e7bd..5b23cb767 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt +++ b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt @@ -31,7 +31,6 @@ import org.jacodb.actors.impl.actors.WatcherMessage import java.util.concurrent.atomic.AtomicBoolean import kotlin.coroutines.CoroutineContext - internal class UserActorWorker( path: ActorPath, private val channel: Channel, diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt index 4fe3fbb97..50fabe641 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt @@ -33,7 +33,6 @@ import org.jacodb.ifds.messages.SubscriptionOnEnd import org.jacodb.ifds.messages.SubscriptionOnStart import org.jacodb.ifds.messages.UnresolvedCall - fun interface ChunkResolver { fun chunkByMessage(message: RunnerMessage): Chunk } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt index 55d448c44..aa36b7601 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt @@ -16,13 +16,13 @@ package org.jacodb.ifds -import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorFactory +import org.jacodb.actors.api.ActorRef import org.jacodb.ifds.domain.Analyzer import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.IndirectionMessage +import org.jacodb.ifds.messages.RunnerMessage interface IfdsContext { fun chunkByMessage(message: RunnerMessage): Chunk diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt index a652683f5..66da1d0a4 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt @@ -21,8 +21,8 @@ import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.signal.Signal import org.jacodb.actors.impl.routing.messageKeyRouter -import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.IfdsContext +import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewChunk import org.jacodb.ifds.messages.RunnerMessage @@ -58,6 +58,7 @@ class ChunkManager( Signal.Start -> { parent.send(NewChunk(chunk)) } + Signal.PostStop -> { // TODO: explain why we do nothing here // do nothing diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt index 78ae745e7..c34e7bdae 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt @@ -18,5 +18,5 @@ package org.jacodb.ifds.domain data class Edge( val from: Vertex, - val to: Vertex + val to: Vertex, ) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt index ab439803b..50a0ce862 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt @@ -29,4 +29,4 @@ class FlowScope( fun addAll(messages: Collection) { this.messages.addAll(messages) } -} \ No newline at end of file +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt index b0d818916..cef643608 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt @@ -24,7 +24,7 @@ sealed interface Reason { ) : Reason data class CallToReturn( - val edge: Edge + val edge: Edge, ) : Reason data class CallToStart( diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt index 9b4941308..7f2f19d8f 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt @@ -16,4 +16,4 @@ package org.jacodb.ifds.domain -interface RunnerId \ No newline at end of file +interface RunnerId diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt index c577f10e3..dcf45864b 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt @@ -18,5 +18,5 @@ package org.jacodb.ifds.domain data class Vertex( val stmt: Stmt, - val fact: Fact -) \ No newline at end of file + val fact: Fact, +) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt index e650c85cf..120cc9205 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt @@ -22,4 +22,4 @@ sealed interface CommonMessage sealed interface RunnerMessage : CommonMessage { val runnerId: RunnerId -} \ No newline at end of file +} diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt index 22e475699..2d7cec961 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt @@ -24,10 +24,10 @@ import org.jacodb.ifds.result.IfdsComputationData sealed interface ProjectMessage : CommonMessage data class NewChunk( - val chunk: Chunk + val chunk: Chunk, ) : ProjectMessage data class CollectAll( val runnerId: RunnerId, - val result: CompletableDeferred>> + val result: CompletableDeferred>>, ) : ProjectMessage diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt index d52acbfd9..4ed7c5dfc 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt +++ b/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt @@ -18,7 +18,6 @@ package org.jacodb.ifds.result import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.domain.Vertex /** From af379f2ed25e471c6d344356fea520b1f74d98a1 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Mon, 22 Apr 2024 16:06:42 +0300 Subject: [PATCH 25/64] [ifds] chore: make collectNpeResults similar to collectTaintResults --- .../org/jacodb/ifds/npe/SystemExtensions.kt | 15 ++++++++++----- .../org/jacodb/ifds/taint/SystemExtensions.kt | 12 +++--------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt index 556839341..5beea6db4 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -20,7 +20,6 @@ import org.jacodb.actors.api.ActorSystem import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.npe.NpeAnalyzer import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge @@ -32,6 +31,7 @@ import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.mergeIfdsResults import org.jacodb.impl.features.usagesExt +import org.jacodb.analysis.taint.TaintVulnerability as JcTaintVulnerability suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath @@ -46,11 +46,16 @@ suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { } } -suspend fun ActorSystem.collectNpeResults(): List { +suspend fun ActorSystem.collectNpeResults(): List = + collectNpeComputationData() + .results + .mapTo(mutableListOf()) { it.vulnerability } + +suspend fun ActorSystem.collectNpeComputationData(): IfdsComputationData { val results = ask { CollectAll(SingleRunner, it) } @Suppress("UNCHECKED_CAST") - val mergedData = - mergeIfdsResults(results.values as Collection>) - return mergedData.results.mapTo(mutableListOf()) { it.vulnerability } + val ifdsData = results.values as Collection> + + return mergeIfdsResults(ifdsData) } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index 70aa6c7d4..87d575741 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -53,16 +53,10 @@ suspend fun ActorSystem.collectTaintResults(): List.collectTaintComputationData(): IfdsComputationData { - val results = ask { - CollectAll( - ForwardRunner, - it - ) - } + val results = ask { CollectAll(ForwardRunner, it) } @Suppress("UNCHECKED_CAST") - val mergedData = - mergeIfdsResults(results.values as Collection>) + val ifdsData = results.values as Collection> - return mergedData + return mergeIfdsResults(ifdsData) } From 411d7f60b7443312d21466c17164760f33945b34 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Mon, 22 Apr 2024 16:25:38 +0300 Subject: [PATCH 26/64] [ifds] fix: cancel "stop-after-timeout" job --- .../analysis/impl/JodaDateTimeAnalysisTest.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt index 92b93c1b5..9a6c47e7b 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt @@ -79,14 +79,16 @@ class JodaDateTimeAnalysisTest : BaseTest() { for (method in methods) { system.startTaintAnalysis(method) } - launch { + val stopper = launch { delay(20.seconds) + logger.info { "Timeout! Stopping the system..." } system.stop() + system.resume() } system.awaitCompletion() - system.resume() - val sinks = system.collectTaintResults() + stopper.cancel() + val sinks = system.collectTaintResults() logger.info { "Vulnerabilities found: ${sinks.size}" } } @@ -100,14 +102,16 @@ class JodaDateTimeAnalysisTest : BaseTest() { for (method in methods) { system.startNpeAnalysis(method) } - launch { + val stopper = launch { delay(20.seconds) + logger.info { "Timeout! Stopping the system..." } system.stop() + system.resume() } system.awaitCompletion() - system.resume() - val sinks = system.collectNpeResults() + stopper.cancel() + val sinks = system.collectNpeResults() logger.info { "Vulnerabilities found: ${sinks.size}" } } From e7abe19203db690c846f40d24af8ba777b89a6aa Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Mon, 22 Apr 2024 16:37:47 +0300 Subject: [PATCH 27/64] [ifds] fix: resume after await --- .../org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt index 9a6c47e7b..668065217 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt @@ -83,10 +83,10 @@ class JodaDateTimeAnalysisTest : BaseTest() { delay(20.seconds) logger.info { "Timeout! Stopping the system..." } system.stop() - system.resume() } system.awaitCompletion() stopper.cancel() + system.resume() val sinks = system.collectTaintResults() logger.info { "Vulnerabilities found: ${sinks.size}" } @@ -106,10 +106,10 @@ class JodaDateTimeAnalysisTest : BaseTest() { delay(20.seconds) logger.info { "Timeout! Stopping the system..." } system.stop() - system.resume() } system.awaitCompletion() stopper.cancel() + system.resume() val sinks = system.collectNpeResults() logger.info { "Vulnerabilities found: ${sinks.size}" } From 1d978d5a038060371bdcef4043a0a1eb53f69d25 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Mon, 6 May 2024 14:26:05 +0300 Subject: [PATCH 28/64] [ifds] fix: review comments --- .../actors/build.gradle.kts | 0 .../kotlin/org/jacodb/actors/api/Actor.kt | 0 .../org/jacodb/actors/api/ActorContext.kt | 0 .../org/jacodb/actors/api/ActorFactory.kt | 0 .../kotlin/org/jacodb/actors/api/ActorPath.kt | 0 .../kotlin/org/jacodb/actors/api/ActorRef.kt | 0 .../org/jacodb/actors/api/ActorSpawner.kt | 0 .../org/jacodb/actors/api/ActorStatus.kt | 0 .../org/jacodb/actors/api/ActorSystem.kt | 0 .../actors/api/options/ChannelFactory.kt | 0 .../jacodb/actors/api/options/SpawnOptions.kt | 0 .../org/jacodb/actors/api/signal/Signal.kt | 0 .../jacodb/actors/impl/ActorContextImpl.kt | 0 .../org/jacodb/actors/impl/ActorPathImpl.kt | 0 .../jacodb/actors/impl/ActorSpawnerImpl.kt | 0 .../org/jacodb/actors/impl/ActorSystemImpl.kt | 3 +- .../jacodb/actors/impl/actors/WatcherActor.kt | 0 .../actors/impl/actors/WatcherMessages.kt | 0 .../jacodb/actors/impl/routing/Builders.kt | 0 .../actors/impl/routing/MessageKeyRouter.kt | 0 .../actors/impl/routing/RandomRouter.kt | 0 .../actors/impl/routing/RoundRobinRouter.kt | 0 .../jacodb/actors/impl/workers/ActorWorker.kt | 0 .../impl/workers/InternalActorWorker.kt | 0 .../actors/impl/workers/UserActorWorker.kt | 0 .../kotlin/org/jacodb/actors/StoppingTest.kt | 4 +-- .../ifds/build.gradle.kts | 2 +- .../kotlin/org/jacodb/ifds/ChunkResolver.kt | 0 .../kotlin/org/jacodb/ifds/IfdsContext.kt | 0 .../org/jacodb/ifds/actors/ChunkManager.kt | 0 .../org/jacodb/ifds/actors/ProjectManager.kt | 0 .../kotlin/org/jacodb/ifds/actors/Runner.kt | 0 .../org/jacodb/ifds/actors/RunnerStorage.kt | 0 .../kotlin/org/jacodb/ifds/actors/Worker.kt | 0 .../kotlin/org/jacodb/ifds/domain/Analyzer.kt | 0 .../kotlin/org/jacodb/ifds/domain/Chunk.kt | 0 .../kotlin/org/jacodb/ifds/domain/Edge.kt | 0 .../org/jacodb/ifds/domain/FlowFunctions.kt | 3 +- .../org/jacodb/ifds/domain/FlowScope.kt | 0 .../kotlin/org/jacodb/ifds/domain/Reason.kt | 0 .../kotlin/org/jacodb/ifds/domain/RunnerId.kt | 0 .../kotlin/org/jacodb/ifds/domain/Vertex.kt | 0 .../jacodb/ifds/messages/AnalyzerMessages.kt | 0 .../org/jacodb/ifds/messages/CommonMessage.kt | 20 +++++++++++ .../ifds/messages/IndirectionMessages.kt | 0 .../jacodb/ifds/messages/ProjectMessages.kt | 0 .../org/jacodb/ifds/messages/RunnerMessage.kt | 4 +-- .../jacodb/ifds/messages/StorageMessages.kt | 0 .../org/jacodb/ifds/result/EagerTraceGraph.kt | 0 .../jacodb/ifds/result/IfdsComputationData.kt | 0 .../org/jacodb/ifds/result/IfdsResult.kt | 0 .../kotlin/org/jacodb/ifds/result/Merging.kt | 4 +-- .../org/jacodb/ifds/result/TraceGraph.kt | 0 jacodb-analysis/{ => taint}/build.gradle.kts | 4 +-- .../org/jacodb/analysis/config/Condition.kt | 0 .../org/jacodb/analysis/config/Position.kt | 0 .../org/jacodb/analysis/config/TaintAction.kt | 0 .../analysis/graph/ApplicationGraphFactory.kt | 0 .../jacodb/analysis/graph/BackwardGraphs.kt | 0 .../analysis/graph/JcApplicationGraphImpl.kt | 0 .../org/jacodb/analysis/graph/JcNoopInst.kt | 0 .../graph/SimplifiedJcApplicationGraph.kt | 0 .../org/jacodb/analysis/ifds/AccessPath.kt | 0 .../org/jacodb/analysis/ifds/Accessors.kt | 0 .../org/jacodb/analysis/ifds/Analyzer.kt | 0 .../kotlin/org/jacodb/analysis/ifds/Edge.kt | 0 .../org/jacodb/analysis/ifds/FlowFunctions.kt | 0 .../org/jacodb/analysis/ifds/IfdsResult.kt | 0 .../org/jacodb/analysis/ifds/Manager.kt | 0 .../kotlin/org/jacodb/analysis/ifds/Maybe.kt | 0 .../kotlin/org/jacodb/analysis/ifds/Reason.kt | 0 .../kotlin/org/jacodb/analysis/ifds/Runner.kt | 0 .../org/jacodb/analysis/ifds/Summary.kt | 0 .../org/jacodb/analysis/ifds/TraceGraph.kt | 0 .../org/jacodb/analysis/ifds/UnitResolver.kt | 0 .../kotlin/org/jacodb/analysis/ifds/Vertex.kt | 0 .../impl/custom/AbstractFlowAnalysis.kt | 0 .../impl/custom/BackwardFlowAnalysis.kt | 0 .../analysis/impl/custom/FlowAnalysis.kt | 0 .../analysis/impl/custom/FlowAnalysisImpl.kt | 0 .../impl/custom/ForwardFlowAnalysis.kt | 0 .../impl/custom/NullAssumptionAnalysis.kt | 0 .../custom/ReachingDefinitionsAnalysis.kt | 0 .../org/jacodb/analysis/npe/NpeAnalyzers.kt | 0 .../jacodb/analysis/npe/NpeFlowFunctions.kt | 2 +- .../org/jacodb/analysis/npe/NpeManager.kt | 0 .../kotlin/org/jacodb/analysis/npe/Utils.kt | 0 .../kotlin/org/jacodb/analysis/sarif/Sarif.kt | 0 .../analysis/sarif/SourceFileResolver.kt | 0 .../jacodb/analysis/sarif/Vulnerability.kt | 0 .../kotlin/org/jacodb/analysis/taint/Sarif.kt | 0 .../jacodb/analysis/taint/TaintAnalyzers.kt | 0 .../jacodb/analysis/taint/TaintBidiRunner.kt | 0 .../org/jacodb/analysis/taint/TaintEvents.kt | 0 .../org/jacodb/analysis/taint/TaintFacts.kt | 0 .../analysis/taint/TaintFlowFunctions.kt | 0 .../org/jacodb/analysis/taint/TaintManager.kt | 0 .../jacodb/analysis/taint/TaintSummaries.kt | 0 .../kotlin/org/jacodb/analysis/taint/Types.kt | 0 .../org/jacodb/analysis/unused/Sarif.kt | 0 .../analysis/unused/UnusedVariableAnalyzer.kt | 0 .../analysis/unused/UnusedVariableEvents.kt | 0 .../analysis/unused/UnusedVariableFacts.kt | 0 .../unused/UnusedVariableFlowFunctions.kt | 0 .../analysis/unused/UnusedVariableManager.kt | 0 .../unused/UnusedVariableSummaries.kt | 0 .../org/jacodb/analysis/unused/Utils.kt | 0 .../kotlin/org/jacodb/analysis/util/Utils.kt | 0 .../kotlin/org/jacodb/ifds/ChunkStrategies.kt | 6 ++-- .../kotlin/org/jacodb/ifds/DefaultAnalyzer.kt | 12 +++---- .../kotlin/org/jacodb/ifds/FunctionWrapper.kt | 4 +-- .../org/jacodb/ifds/IndirectionHandler.kt | 0 .../kotlin/org/jacodb/ifds/JcIfdsContext.kt | 6 ++-- .../kotlin/org/jacodb/ifds/npe/Context.kt | 2 +- .../kotlin/org/jacodb/ifds/npe/Results.kt | 0 .../kotlin/org/jacodb/ifds/npe/Runners.kt | 2 +- .../org/jacodb/ifds/npe/SystemExtensions.kt | 4 +-- .../kotlin/org/jacodb/ifds/sarif/Sarif.kt | 0 .../jacodb/ifds/sarif/SourceFileResolver.kt | 0 .../org/jacodb/ifds/sarif/Vulnerability.kt | 0 .../kotlin/org/jacodb/ifds/taint/Context.kt | 8 ++--- .../kotlin/org/jacodb/ifds/taint/Results.kt | 0 .../kotlin/org/jacodb/ifds/taint/Runners.kt | 4 +-- .../org/jacodb/ifds/taint/SystemExtensions.kt | 4 +-- .../kotlin/org/jacodb/ifds/unused/Context.kt | 2 +- .../kotlin/org/jacodb/ifds/unused/Results.kt | 0 .../kotlin/org/jacodb/ifds/unused/Runners.kt | 2 +- .../jacodb/ifds/unused/SystemExtensions.kt | 4 +-- .../analysis/impl/JavaAnalysisApiTest.java | 0 .../jacodb/analysis/impl/BaseAnalysisTest.kt | 0 .../analysis/impl/ConditionEvaluatorTest.kt | 0 .../org/jacodb/analysis/impl/IfdsNpeTest.kt | 4 +-- .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 8 ++--- .../jacodb/analysis/impl/IfdsUnusedTest.kt | 4 +-- .../analysis/impl/JodaDateTimeAnalysisTest.kt | 8 ++--- .../impl/NullabilityAssumptionAnalysisTest.kt | 0 .../analysis/impl/TaintFlowFunctionsTest.kt | 0 .../src/test/resources/additional.json | 0 .../src/test/resources/config_small.json | 0 .../src/test/resources/config_test.json | 0 .../src/test/resources/pointerbench.jar | Bin .../test/resources/simplelogger.properties | 0 .../org/jacodb/actors/impl/util/Adapters.kt | 34 ------------------ settings.gradle.kts | 7 ++-- 144 files changed, 77 insertions(+), 94 deletions(-) rename {jacodb-ifds => jacodb-analysis}/actors/build.gradle.kts (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/ActorPath.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/options/ChannelFactory.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt (95%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt (100%) rename {jacodb-ifds => jacodb-analysis}/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt (95%) rename {jacodb-ifds => jacodb-analysis}/ifds/build.gradle.kts (77%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt (100%) rename jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt => jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunctions.kt (92%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt (100%) create mode 100644 jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessage.kt rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt (100%) rename jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt => jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/RunnerMessage.kt (95%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt (100%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt (94%) rename {jacodb-ifds => jacodb-analysis}/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt (100%) rename jacodb-analysis/{ => taint}/build.gradle.kts (89%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/config/Condition.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/config/Position.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/Maybe.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt (99%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/taint/Types.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/analysis/util/Utils.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt (93%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt (94%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt (98%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt (91%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/npe/Context.kt (97%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/npe/Results.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt (94%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt (93%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/taint/Context.kt (93%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/taint/Results.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt (89%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt (94%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/unused/Context.kt (96%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/unused/Results.kt (100%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt (94%) rename jacodb-analysis/{ => taint}/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt (96%) rename jacodb-analysis/{ => taint}/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java (100%) rename jacodb-analysis/{ => taint}/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt (100%) rename jacodb-analysis/{ => taint}/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt (100%) rename jacodb-analysis/{ => taint}/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt (98%) rename jacodb-analysis/{ => taint}/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt (95%) rename jacodb-analysis/{ => taint}/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt (96%) rename jacodb-analysis/{ => taint}/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt (94%) rename jacodb-analysis/{ => taint}/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt (100%) rename jacodb-analysis/{ => taint}/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt (100%) rename jacodb-analysis/{ => taint}/src/test/resources/additional.json (100%) rename jacodb-analysis/{ => taint}/src/test/resources/config_small.json (100%) rename jacodb-analysis/{ => taint}/src/test/resources/config_test.json (100%) rename jacodb-analysis/{ => taint}/src/test/resources/pointerbench.jar (100%) rename jacodb-analysis/{ => taint}/src/test/resources/simplelogger.properties (100%) delete mode 100644 jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/util/Adapters.kt diff --git a/jacodb-ifds/actors/build.gradle.kts b/jacodb-analysis/actors/build.gradle.kts similarity index 100% rename from jacodb-ifds/actors/build.gradle.kts rename to jacodb-analysis/actors/build.gradle.kts diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorPath.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorPath.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorPath.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorPath.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorRef.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSpawner.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorStatus.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/ChannelFactory.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/ChannelFactory.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/ChannelFactory.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/ChannelFactory.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorPathImpl.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt similarity index 95% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 4851b7087..037dca00d 100644 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -75,8 +75,7 @@ internal class ActorSystemImpl( } } -// TODO: consider just 'system', because 'Of' implies a vararg, which is not the case here -fun systemOf( +fun system( name: String, options: SpawnOptions = SpawnOptions.default, actorFactory: ActorFactory, diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RoundRobinRouter.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt similarity index 100% rename from jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt diff --git a/jacodb-ifds/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt b/jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt similarity index 95% rename from jacodb-ifds/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt rename to jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt index ccb2c4015..77cbdf004 100644 --- a/jacodb-ifds/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt +++ b/jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt @@ -23,7 +23,7 @@ import kotlinx.coroutines.withTimeoutOrNull import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef -import org.jacodb.actors.impl.systemOf +import org.jacodb.actors.impl.system import org.junit.jupiter.api.Test import kotlin.test.assertNotNull import kotlin.test.assertTrue @@ -51,7 +51,7 @@ class StoppingTest { @Test fun testStops() = runBlocking { - val system = systemOf("test") { Repeater(null, 2) } + val system = system("test") { Repeater(null, 2) } system.send(0) val job = launch { diff --git a/jacodb-ifds/ifds/build.gradle.kts b/jacodb-analysis/ifds/build.gradle.kts similarity index 77% rename from jacodb-ifds/ifds/build.gradle.kts rename to jacodb-analysis/ifds/build.gradle.kts index da3056149..51110e42d 100644 --- a/jacodb-ifds/ifds/build.gradle.kts +++ b/jacodb-analysis/ifds/build.gradle.kts @@ -3,7 +3,7 @@ dependencies { implementation(Libs.slf4j_simple) implementation(Libs.kotlinx_coroutines_core) - implementation(project(":jacodb-ifds:actors")) + implementation(project(":jacodb-analysis:actors")) testImplementation(kotlin("test")) } diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunctions.kt similarity index 92% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunctions.kt index f292ebbbf..fab06b82d 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunction.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunctions.kt @@ -16,8 +16,7 @@ package org.jacodb.ifds.domain -// TODO: consider 'FlowFunctions' (plural) -interface FlowFunction { +interface FlowFunctions { fun FlowScope.sequent( next: Stmt, ) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessage.kt new file mode 100644 index 000000000..4b341019f --- /dev/null +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessage.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.messages + +sealed interface CommonMessage + diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/RunnerMessage.kt similarity index 95% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/RunnerMessage.kt index 120cc9205..8a095af29 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/RunnerMessage.kt @@ -18,8 +18,6 @@ package org.jacodb.ifds.messages import org.jacodb.ifds.domain.RunnerId -sealed interface CommonMessage - sealed interface RunnerMessage : CommonMessage { val runnerId: RunnerId -} +} \ No newline at end of file diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt similarity index 94% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt index 905ee7b13..bcf06581c 100644 --- a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt @@ -21,13 +21,13 @@ import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex fun > mergeIfdsResults( - ifdsDatas: Collection>, + ifdsResults: Collection>, ): IfdsComputationData { val edgesByEnd = hashMapOf, HashSet>>() val factsByStmt = hashMapOf>() val reasonsByEdge = hashMapOf, HashSet>>() val results = hashSetOf() - for (data in ifdsDatas) { + for (data in ifdsResults) { for ((end, edges) in data.edgesByEnd) { edgesByEnd.getOrPut(end, ::hashSetOf) .addAll(edges) diff --git a/jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt similarity index 100% rename from jacodb-ifds/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt diff --git a/jacodb-analysis/build.gradle.kts b/jacodb-analysis/taint/build.gradle.kts similarity index 89% rename from jacodb-analysis/build.gradle.kts rename to jacodb-analysis/taint/build.gradle.kts index 19e3a7544..18d46dbd8 100644 --- a/jacodb-analysis/build.gradle.kts +++ b/jacodb-analysis/taint/build.gradle.kts @@ -8,8 +8,8 @@ dependencies { api(project(":jacodb-api")) api(project(":jacodb-taint-configuration")) - implementation(project(":jacodb-ifds:actors")) - implementation(project(":jacodb-ifds:ifds")) + implementation(project(":jacodb-analysis:actors")) + implementation(project(":jacodb-analysis:ifds")) implementation(Libs.kotlin_logging) implementation(Libs.slf4j_simple) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Condition.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/Condition.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Condition.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/Condition.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Position.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/Position.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/Position.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/Position.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Maybe.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Maybe.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Maybe.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Maybe.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt similarity index 99% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt index f64c922a4..dbdbfec98 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt @@ -550,7 +550,7 @@ class ForwardNpeFlowFunctions( ) = FlowFunction { fact -> // TODO: do we even need to return non-empty list for zero fact here? if (fact == TaintZeroFact) { - // return@FlowFunction listOf(Zero) + // return@FlowFunctions listOf(Zero) return@FlowFunction buildSet { add(TaintZeroFact) if (exitStatement is JcReturnInst && callStatement is JcAssignInst) { diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Types.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/taint/Types.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/util/Utils.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/analysis/util/Utils.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/util/Utils.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt similarity index 93% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt index 1b2afe658..cd5d0e986 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt @@ -23,10 +23,10 @@ import org.jacodb.api.ext.packageName import org.jacodb.ifds.domain.Chunk // TODO: consider 'SingletonChunk' -data object SingleChunk : Chunk +data object SingletonChunk : Chunk -val SingleChunkStrategy = ChunkStrategy { - SingleChunk +val SingletonChunkStrategy = ChunkStrategy { + SingletonChunk } data class MethodChunk( diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt similarity index 94% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt index 0693a577e..dfc3c38d2 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt @@ -18,7 +18,7 @@ package org.jacodb.ifds import org.jacodb.ifds.domain.Analyzer import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.FlowFunction +import org.jacodb.ifds.domain.FlowFunctions import org.jacodb.ifds.domain.FlowScope import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.AnalyzerMessage @@ -36,7 +36,7 @@ typealias TaintFlowScope = FlowScope class DefaultAnalyzer( private val applicationGraph: JcApplicationGraph, - private val flowFunction: FlowFunction, + private val flowFunctions: FlowFunctions, private val runnerId: RunnerId, ) : Analyzer { override fun step(message: AnalyzerMessage): Collection = buildList { @@ -82,7 +82,7 @@ class DefaultAnalyzer( val successors = applicationGraph.successors(edge.to.stmt) - flowFunction.run { + flowFunctions.run { for (successor in successors) { callToReturn(successor) } @@ -92,7 +92,7 @@ class DefaultAnalyzer( private fun TaintFlowScope.processSequent(edge: Edge) { val successors = applicationGraph.successors(edge.to.stmt) - flowFunction.run { + flowFunctions.run { for (successor in successors) { sequent(successor) } @@ -105,7 +105,7 @@ class DefaultAnalyzer( ) { val entryPoints = applicationGraph.entryPoints(resolvedCall.method) - flowFunction.run { + flowFunctions.run { for (entryPoint in entryPoints) { callToStart(entryPoint) } @@ -116,7 +116,7 @@ class DefaultAnalyzer( private fun TaintFlowScope.processNotificationOnStart(message: NotificationOnStart) { val successors = applicationGraph.successors(message.data.to.stmt) - flowFunction.run { + flowFunctions.run { for (successor in successors) { exitToReturnSite(message.data, successor) } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt similarity index 98% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt index ff12d2210..c3a919308 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt @@ -19,7 +19,7 @@ package org.jacodb.ifds import org.jacodb.analysis.ifds.Analyzer import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.FlowFunction +import org.jacodb.ifds.domain.FlowFunctions import org.jacodb.ifds.domain.FlowScope import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId @@ -33,7 +33,7 @@ class JcFlowFunctionsAdapter( private val runnerId: RunnerId, private val jcAnalyzer: Analyzer, private val jcEventProcessor: JcEventProcessor, -) : FlowFunction { +) : FlowFunctions { private val jcFlowFunctions = jcAnalyzer.flowFunctions override fun FlowScope.sequent(next: JcInst) = diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt similarity index 91% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt index ad2123b82..87e83aeef 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt @@ -23,7 +23,7 @@ import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Analyzer import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.domain.FlowFunction +import org.jacodb.ifds.domain.FlowFunctions import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.impl.features.HierarchyExtensionImpl @@ -33,7 +33,7 @@ class JcIfdsContext( private val graph: JcApplicationGraph, private val bannedPackagePrefixes: List, private val chunkStrategy: ChunkResolver, - private val flowFunctionFactory: (RunnerId) -> FlowFunction, + private val flowFunctionsFactory: (RunnerId) -> FlowFunctions, ) : IfdsContext { override fun chunkByMessage(message: RunnerMessage): Chunk = chunkStrategy.chunkByMessage(message) @@ -44,7 +44,7 @@ class JcIfdsContext( override fun getAnalyzer(chunk: Chunk, runnerId: RunnerId): Analyzer = DefaultAnalyzer( graph, - flowFunctionFactory(runnerId), + flowFunctionsFactory(runnerId), runnerId ) diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt similarity index 97% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt index 1d4c74784..25b8267e5 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -44,7 +44,7 @@ fun npeIfdsContext( chunkStrategy ) { runnerId -> val analyzer = when (runnerId) { - is SingleRunner -> NpeAnalyzer(graph) + is SingletonRunnerId -> NpeAnalyzer(graph) else -> error("Unexpected runnerId: $runnerId") } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt similarity index 94% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt index e4865f7cd..5ce7ed09e 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt @@ -18,4 +18,4 @@ package org.jacodb.ifds.npe import org.jacodb.ifds.domain.RunnerId -data object SingleRunner : RunnerId +data object SingletonRunnerId : RunnerId diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt similarity index 93% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt index 5beea6db4..56110d585 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -40,7 +40,7 @@ suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { for (fact in npeAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { val vertex = Vertex(entryPoint, fact) - val message = NewEdge(SingleRunner, Edge(vertex, vertex), Reason.Initial) + val message = NewEdge(SingletonRunnerId, Edge(vertex, vertex), Reason.Initial) send(message) } } @@ -52,7 +52,7 @@ suspend fun ActorSystem.collectNpeResults(): List.collectNpeComputationData(): IfdsComputationData { - val results = ask { CollectAll(SingleRunner, it) } + val results = ask { CollectAll(SingletonRunnerId, it) } @Suppress("UNCHECKED_CAST") val ifdsData = results.values as Collection> diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt similarity index 93% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt index 01a86e090..c07fc2d8a 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -38,8 +38,8 @@ import org.jacodb.ifds.messages.NewSummaryEdge as IfdsNewSummaryEdge private fun complementRunner(type: RunnerId): RunnerId = when (type) { - ForwardRunner -> BackwardRunner - BackwardRunner -> ForwardRunner + ForwardRunnerId -> BackwardRunnerId + BackwardRunnerId -> ForwardRunnerId else -> error("unexpected runner: $type") } @@ -57,8 +57,8 @@ fun taintIfdsContext( chunkStrategy ) { runnerId -> val analyzer = when (runnerId) { - is ForwardRunner -> TaintAnalyzer(graph) - is BackwardRunner -> BackwardTaintAnalyzer(graph) + is ForwardRunnerId -> TaintAnalyzer(graph) + is BackwardRunnerId -> BackwardTaintAnalyzer(graph) else -> error("Unexpected runnerId: $runnerId") } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Results.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt similarity index 89% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt index e96d4c8d7..42339ff21 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt @@ -18,5 +18,5 @@ package org.jacodb.ifds.taint import org.jacodb.ifds.domain.RunnerId -data object ForwardRunner : RunnerId -data object BackwardRunner : RunnerId +data object ForwardRunnerId : RunnerId +data object BackwardRunnerId : RunnerId diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt similarity index 94% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index 87d575741..a525e1472 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -41,7 +41,7 @@ suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { for (fact in taintAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { val vertex = Vertex(entryPoint, fact) - val message = NewEdge(ForwardRunner, Edge(vertex, vertex), Reason.Initial) + val message = NewEdge(ForwardRunnerId, Edge(vertex, vertex), Reason.Initial) send(message) } } @@ -53,7 +53,7 @@ suspend fun ActorSystem.collectTaintResults(): List.collectTaintComputationData(): IfdsComputationData { - val results = ask { CollectAll(ForwardRunner, it) } + val results = ask { CollectAll(ForwardRunnerId, it) } @Suppress("UNCHECKED_CAST") val ifdsData = results.values as Collection> diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt similarity index 96% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt index fe0ec732a..bd1c6de35 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt @@ -40,7 +40,7 @@ fun unusedIfdsContext( chunkStrategy ) { runnerId -> val analyzer = when (runnerId) { - is SingleRunner -> UnusedVariableAnalyzer(graph) + is SingletonRunnerId -> UnusedVariableAnalyzer(graph) else -> error("Unexpected runnerId: $runnerId") } diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt similarity index 100% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Results.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt similarity index 94% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt index 453b0d412..5f0370017 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt @@ -18,4 +18,4 @@ package org.jacodb.ifds.unused import org.jacodb.ifds.domain.RunnerId -data object SingleRunner : RunnerId +data object SingletonRunnerId : RunnerId diff --git a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt similarity index 96% rename from jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt index a61e7b155..9bb44a39c 100644 --- a/jacodb-analysis/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -44,7 +44,7 @@ suspend fun ActorSystem.startUnusedAnalysis(method: JcMethod) { for (fact in unusedAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { val vertex = Vertex(entryPoint, fact) - val message = NewEdge(SingleRunner, Edge(vertex, vertex), Reason.Initial) + val message = NewEdge(SingletonRunnerId, Edge(vertex, vertex), Reason.Initial) send(message) } } @@ -79,7 +79,7 @@ suspend fun ActorSystem.collectUnusedResult(): List.collectUnusedComputationData(): IfdsComputationData { val results = ask { CollectAll( - SingleRunner, + SingletonRunnerId, it ) } diff --git a/jacodb-analysis/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java similarity index 100% rename from jacodb-analysis/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java rename to jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt similarity index 100% rename from jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt similarity index 100% rename from jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt similarity index 98% rename from jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt index b650fca49..2918e40bf 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt @@ -17,7 +17,7 @@ package org.jacodb.analysis.impl import kotlinx.coroutines.runBlocking -import org.jacodb.actors.impl.systemOf +import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.taint.TaintVulnerability @@ -200,7 +200,7 @@ class IfdsNpeTest : BaseAnalysisTest() { private fun findSinks(method: JcMethod): List = runBlocking { val ifdsContext = npeIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = systemOf("ifds") { ProjectManager(ifdsContext) } + val system = system("ifds") { ProjectManager(ifdsContext) } system.startNpeAnalysis(method) system.awaitCompletion() diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt similarity index 95% rename from jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index b19c986a3..cc189a067 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -19,7 +19,7 @@ package org.jacodb.analysis.impl import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import org.jacodb.actors.impl.systemOf +import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.analysis.taint.TaintZeroFact @@ -69,7 +69,7 @@ class IfdsSqlTest : BaseAnalysisTest() { val method = cp.findClass().declaredMethods.single { it.name == methodName } val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = systemOf("ifds") { ProjectManager(ifdsContext) } + val system = system("ifds") { ProjectManager(ifdsContext) } system.startTaintAnalysis(method) system.awaitCompletion() @@ -84,7 +84,7 @@ class IfdsSqlTest : BaseAnalysisTest() { private fun findSinks(method: JcMethod): List = runBlocking { val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = systemOf("ifds") { ProjectManager(ifdsContext) } + val system = system("ifds") { ProjectManager(ifdsContext) } system.startTaintAnalysis(method) system.awaitCompletion() @@ -114,7 +114,7 @@ class IfdsSqlTest : BaseAnalysisTest() { val badMethod = clazz.methods.single { it.name == "bad" } val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes, useBackwardRunner = true) - val system = systemOf("ifds") { ProjectManager(ifdsContext) } + val system = system("ifds") { ProjectManager(ifdsContext) } system.startTaintAnalysis(badMethod) system.awaitCompletion() diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt similarity index 96% rename from jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt index e87dd16ad..6ed961014 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt @@ -17,7 +17,7 @@ package org.jacodb.analysis.impl import kotlinx.coroutines.runBlocking -import org.jacodb.actors.impl.systemOf +import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.unused.UnusedVariableVulnerability import org.jacodb.api.JcMethod @@ -63,7 +63,7 @@ class IfdsUnusedTest : BaseAnalysisTest() { private fun findSinks(method: JcMethod): List = runBlocking { val ifdsContext = unusedIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = systemOf("ifds") { ProjectManager(ifdsContext) } + val system = system("ifds") { ProjectManager(ifdsContext) } system.startUnusedAnalysis(method) system.awaitCompletion() diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt similarity index 94% rename from jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt index 668065217..ed997cb11 100644 --- a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt @@ -19,7 +19,7 @@ package org.jacodb.analysis.impl import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking -import org.jacodb.actors.impl.systemOf +import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.api.JcClasspath @@ -74,7 +74,7 @@ class JodaDateTimeAnalysisTest : BaseTest() { val methods = clazz.declaredMethods val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = systemOf("ifds") { ProjectManager(ifdsContext) } + val system = system("ifds") { ProjectManager(ifdsContext) } for (method in methods) { system.startTaintAnalysis(method) @@ -97,7 +97,7 @@ class JodaDateTimeAnalysisTest : BaseTest() { val clazz = cp.findClass() val methods = clazz.declaredMethods val ifdsContext = npeIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = systemOf("ifds") { ProjectManager(ifdsContext) } + val system = system("ifds") { ProjectManager(ifdsContext) } for (method in methods) { system.startNpeAnalysis(method) @@ -120,7 +120,7 @@ class JodaDateTimeAnalysisTest : BaseTest() { val clazz = cp.findClass() val methods = clazz.declaredMethods val ifdsContext = unusedIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = systemOf("ifds") { ProjectManager(ifdsContext) } + val system = system("ifds") { ProjectManager(ifdsContext) } for (method in methods) { system.startUnusedAnalysis(method) diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt similarity index 100% rename from jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt diff --git a/jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt similarity index 100% rename from jacodb-analysis/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt diff --git a/jacodb-analysis/src/test/resources/additional.json b/jacodb-analysis/taint/src/test/resources/additional.json similarity index 100% rename from jacodb-analysis/src/test/resources/additional.json rename to jacodb-analysis/taint/src/test/resources/additional.json diff --git a/jacodb-analysis/src/test/resources/config_small.json b/jacodb-analysis/taint/src/test/resources/config_small.json similarity index 100% rename from jacodb-analysis/src/test/resources/config_small.json rename to jacodb-analysis/taint/src/test/resources/config_small.json diff --git a/jacodb-analysis/src/test/resources/config_test.json b/jacodb-analysis/taint/src/test/resources/config_test.json similarity index 100% rename from jacodb-analysis/src/test/resources/config_test.json rename to jacodb-analysis/taint/src/test/resources/config_test.json diff --git a/jacodb-analysis/src/test/resources/pointerbench.jar b/jacodb-analysis/taint/src/test/resources/pointerbench.jar similarity index 100% rename from jacodb-analysis/src/test/resources/pointerbench.jar rename to jacodb-analysis/taint/src/test/resources/pointerbench.jar diff --git a/jacodb-analysis/src/test/resources/simplelogger.properties b/jacodb-analysis/taint/src/test/resources/simplelogger.properties similarity index 100% rename from jacodb-analysis/src/test/resources/simplelogger.properties rename to jacodb-analysis/taint/src/test/resources/simplelogger.properties diff --git a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/util/Adapters.kt b/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/util/Adapters.kt deleted file mode 100644 index 2342da46c..000000000 --- a/jacodb-ifds/actors/src/main/kotlin/org/jacodb/actors/impl/util/Adapters.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.actors.impl.util - -import org.jacodb.actors.api.ActorPath -import org.jacodb.actors.api.ActorRef - -//fun ActorRef.adaptWith(adapter: (R) -> T?): ActorRef = object : ActorRef{ -// override val path: ActorPath -// get() = this@adaptWith.path -// -// override suspend fun send(message: R) { -// val adaptedMessage = adapter(message) ?: return -// this@adaptWith.send(adaptedMessage) -// } -//} -// -//inline fun ActorRef.adaptType(): ActorRef = adaptWith { message -> -// message as? T -//} diff --git a/settings.gradle.kts b/settings.gradle.kts index 2f7632de4..4dc0c23aa 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,11 +21,12 @@ gitHooks { include("jacodb-api") include("jacodb-core") -include("jacodb-analysis") include("jacodb-examples") include("jacodb-benchmarks") include("jacodb-cli") include("jacodb-approximations") include("jacodb-taint-configuration") -include("jacodb-ifds:actors") -include("jacodb-ifds:ifds") +include("jacodb-analysis:actors") +include("jacodb-analysis:ifds") +include("jacodb-analysis:taint") +findProject(":jacodb-analysis:taint")?.name = "taint" From 4eeaeca361f1b3a39bafc088e89f8a50b5177bf0 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Mon, 13 May 2024 18:31:21 +0300 Subject: [PATCH 29/64] [ifds] wip: remove some old ifds related code --- .../org/jacodb/analysis/ifds/Analyzer.kt | 5 - .../org/jacodb/analysis/ifds/IfdsResult.kt | 130 ------- .../org/jacodb/analysis/ifds/Manager.kt | 39 --- .../kotlin/org/jacodb/analysis/ifds/Reason.kt | 19 -- .../kotlin/org/jacodb/analysis/ifds/Runner.kt | 257 -------------- .../org/jacodb/analysis/ifds/Summary.kt | 67 ---- .../org/jacodb/analysis/ifds/TraceGraph.kt | 66 ---- .../org/jacodb/analysis/ifds/UnitResolver.kt | 92 ----- .../org/jacodb/analysis/npe/NpeAnalyzers.kt | 9 - .../org/jacodb/analysis/npe/NpeManager.kt | 62 ---- .../kotlin/org/jacodb/analysis/sarif/Sarif.kt | 150 -------- .../analysis/sarif/SourceFileResolver.kt | 23 -- .../jacodb/analysis/sarif/Vulnerability.kt | 31 -- .../kotlin/org/jacodb/analysis/taint/Sarif.kt | 33 -- .../jacodb/analysis/taint/TaintAnalyzers.kt | 13 - .../jacodb/analysis/taint/TaintBidiRunner.kt | 144 -------- .../org/jacodb/analysis/taint/TaintManager.kt | 319 ------------------ .../jacodb/analysis/taint/TaintSummaries.kt | 5 - .../kotlin/org/jacodb/analysis/taint/Types.kt | 2 - .../org/jacodb/analysis/unused/Sarif.kt | 28 -- .../analysis/unused/UnusedVariableAnalyzer.kt | 4 - .../analysis/unused/UnusedVariableManager.kt | 260 -------------- .../unused/UnusedVariableSummaries.kt | 6 - .../kotlin/org/jacodb/analysis/util/Utils.kt | 10 - .../analysis/impl/JavaAnalysisApiTest.java | 40 +-- .../jacodb/analysis/impl/BaseAnalysisTest.kt | 1 - 26 files changed, 17 insertions(+), 1798 deletions(-) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt index f38a9be90..158c80c67 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt @@ -22,9 +22,4 @@ interface Analyzer { fun handleNewEdge( edge: Edge, ): List - - fun handleCrossUnitCall( - caller: Vertex, - callee: Vertex, - ): List } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt deleted file mode 100644 index 0584541b1..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/IfdsResult.kt +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.cfg.JcInst - -/** - * Aggregates all facts and edges found by the tabulation algorithm. - */ -class IfdsResult internal constructor( - val pathEdgesBySink: Map, Collection>>, - val facts: Map>, - val reasons: Map, Set>>, - val zeroFact: Fact?, -) { - constructor( - pathEdges: Collection>, - facts: Map>, - reasons: Map, Set>>, - zeroFact: Fact?, - ) : this( - pathEdges.groupByTo(HashMap()) { it.to }, - facts, - reasons, - zeroFact - ) - - fun buildTraceGraph(sink: Vertex): TraceGraph { - val sources: MutableSet> = hashSetOf() - val edges: MutableMap, MutableSet>> = hashMapOf() - val unresolvedCrossUnitCalls: MutableMap, MutableSet>> = hashMapOf() - val visited: MutableSet, Vertex>> = hashSetOf() - - fun addEdge( - from: Vertex, - to: Vertex, - ) { - if (from != to) { - edges.getOrPut(from) { hashSetOf() }.add(to) - } - } - - fun dfs( - edge: Edge, - lastVertex: Vertex, - stopAtMethodStart: Boolean, - ) { - if (!visited.add(edge to lastVertex)) { - return - } - - // Note: loop-edge represents method start - if (stopAtMethodStart && edge.from == edge.to) { - addEdge(edge.from, lastVertex) - return - } - - val vertex = edge.to - if (vertex.fact == zeroFact) { - addEdge(vertex, lastVertex) - sources.add(vertex) - return - } - - for (reason in reasons[edge].orEmpty()) { - when (reason) { - is Reason.Sequent -> { - val predEdge = reason.edge - if (predEdge.to.fact == vertex.fact) { - dfs(predEdge, lastVertex, stopAtMethodStart) - } else { - addEdge(predEdge.to, lastVertex) - dfs(predEdge, predEdge.to, stopAtMethodStart) - } - } - - is Reason.CallToStart -> { - val predEdge = reason.edge - if (!stopAtMethodStart) { - addEdge(predEdge.to, lastVertex) - dfs(predEdge, predEdge.to, false) - } - } - - is Reason.ThroughSummary -> { - val predEdge = reason.edge - val summaryEdge = reason.summaryEdge - addEdge(summaryEdge.to, lastVertex) // Return to next vertex - addEdge(predEdge.to, summaryEdge.from) // Call to start - dfs(summaryEdge, summaryEdge.to, true) // Expand summary edge - dfs(predEdge, predEdge.to, stopAtMethodStart) // Continue normal analysis - } - - is Reason.CrossUnitCall -> { - addEdge(edge.to, lastVertex) - unresolvedCrossUnitCalls.getOrPut(reason.caller) { hashSetOf() }.add(edge.to) - } - - is Reason.External -> { - TODO("External reason is not supported yet") - } - - is Reason.Initial -> { - sources.add(vertex) - addEdge(edge.to, lastVertex) - } - } - } - } - - for (edge in pathEdgesBySink[sink].orEmpty()) { - dfs(edge, edge.to, false) - } - return TraceGraph(sink, sources, edges, unresolvedCrossUnitCalls) - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt deleted file mode 100644 index cc7b2c897..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Manager.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.ifds - -import kotlinx.coroutines.CoroutineScope -import org.jacodb.api.JcMethod - -interface Manager { - fun handleEvent(event: Event) - - fun handleControlEvent(event: ControlEvent) - - fun subscribeOnSummaryEdges( - method: JcMethod, - scope: CoroutineScope, - handler: (Edge) -> Unit, - ) -} - -sealed interface ControlEvent - -data class QueueEmptinessChanged( - val runner: Runner<*>, - val isEmpty: Boolean, -) : ControlEvent diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt index c6600cd62..1ee31a85c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt @@ -17,24 +17,5 @@ package org.jacodb.analysis.ifds sealed interface Reason { - object Initial : Reason - object External : Reason - - data class CrossUnitCall( - val caller: Vertex, - ) : Reason - - data class Sequent( - val edge: Edge, - ) : Reason - - data class CallToStart( - val edge: Edge, - ) : Reason - - data class ThroughSummary( - val edge: Edge, - val summaryEdge: Edge, - ) : Reason } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt deleted file mode 100644 index a8fc4f916..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Runner.kt +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.ifds - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.getOrElse -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.isActive -import org.jacodb.analysis.graph.JcNoopInst -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.api.cfg.JcInst -import org.jacodb.api.ext.cfg.callExpr -import java.util.concurrent.ConcurrentHashMap - -private val logger = mu.KotlinLogging.logger {} - -interface Runner { - val unit: UnitType - - suspend fun run(startMethods: List) - fun submitNewEdge(edge: Edge, reason: Reason) - fun getIfdsResult(): IfdsResult -} - -class UniRunner( - private val graph: JcApplicationGraph, - private val analyzer: Analyzer, - private val manager: Manager, - private val unitResolver: UnitResolver, - override val unit: UnitType, - private val zeroFact: Fact?, -) : Runner { - - private val flowSpace: FlowFunctions = analyzer.flowFunctions - private val workList: Channel> = Channel(Channel.UNLIMITED) - private val reasons = ConcurrentHashMap, MutableSet>>() - internal val pathEdges: MutableSet> = ConcurrentHashMap.newKeySet() - - private val summaryEdges: MutableMap, MutableSet>> = hashMapOf() - private val callerPathEdgeOf: MutableMap, MutableSet>> = hashMapOf() - - private val queueIsEmpty = QueueEmptinessChanged(runner = this, isEmpty = true) - private val queueIsNotEmpty = QueueEmptinessChanged(runner = this, isEmpty = false) - - override suspend fun run(startMethods: List) { - for (method in startMethods) { - addStart(method) - } - - tabulationAlgorithm() - } - - private fun addStart(method: JcMethod) { - require(unitResolver.resolve(method) == unit) - val startFacts = flowSpace.obtainPossibleStartFacts(method) - for (startFact in startFacts) { - for (start in graph.entryPoints(method)) { - val vertex = Vertex(start, startFact) - val edge = Edge(vertex, vertex) // loop - propagate(edge, Reason.Initial) - } - } - } - - override fun submitNewEdge(edge: Edge, reason: Reason) { - propagate(edge, reason) - } - - private fun propagate( - edge: Edge, - reason: Reason, - ): Boolean { - require(unitResolver.resolve(edge.method) == unit) { - "Propagated edge must be in the same unit" - } - - reasons.computeIfAbsent(edge) { ConcurrentHashMap.newKeySet() }.add(reason) - - // Handle only NEW edges: - if (pathEdges.add(edge)) { - val doPrintOnlyForward = true - val doPrintZero = false - if (!doPrintOnlyForward || edge.from.statement is JcNoopInst) { - if (doPrintZero || edge.to.fact != TaintZeroFact) { - logger.trace { "Propagating edge=$edge in method=${edge.method.name} with reason=${reason}" } - } - } - - // Send edge to analyzer/manager: - for (event in analyzer.handleNewEdge(edge)) { - manager.handleEvent(event) - } - - // Add edge to worklist: - workList.trySend(edge).getOrThrow() - - return true - } - - return false - } - - private suspend fun tabulationAlgorithm() = coroutineScope { - while (isActive) { - val edge = workList.tryReceive().getOrElse { - manager.handleControlEvent(queueIsEmpty) - val edge = workList.receive() - manager.handleControlEvent(queueIsNotEmpty) - edge - } - tabulationAlgorithmStep(edge, this@coroutineScope) - } - } - - private val JcMethod.isExtern: Boolean - get() = unitResolver.resolve(this) != unit - - private fun tabulationAlgorithmStep( - currentEdge: Edge, - scope: CoroutineScope, - ) { - val (startVertex, currentVertex) = currentEdge - val (current, currentFact) = currentVertex - - val currentCallees = graph.callees(current).toList() - val currentIsCall = current.callExpr != null - val currentIsExit = current in graph.exitPoints(current.location.method) - - if (currentIsCall) { - // Propagate through the call-to-return-site edge: - for (returnSite in graph.successors(current)) { - val factsAtReturnSite = flowSpace - .obtainCallToReturnSiteFlowFunction(current, returnSite) - .compute(currentFact) - for (returnSiteFact in factsAtReturnSite) { - val returnSiteVertex = Vertex(returnSite, returnSiteFact) - val newEdge = Edge(startVertex, returnSiteVertex) - propagate(newEdge, Reason.Sequent(currentEdge)) - } - } - - // Propagate through the call: - for (callee in currentCallees) { - for (calleeStart in graph.entryPoints(callee)) { - val factsAtCalleeStart = flowSpace - .obtainCallToStartFlowFunction(current, calleeStart) - .compute(currentFact) - for (calleeStartFact in factsAtCalleeStart) { - val calleeStartVertex = Vertex(calleeStart, calleeStartFact) - - if (callee.isExtern) { - // Initialize analysis of callee: - for (event in analyzer.handleCrossUnitCall(currentVertex, calleeStartVertex)) { - manager.handleEvent(event) - } - - // Subscribe on summary edges: - manager.subscribeOnSummaryEdges(callee, scope) { summaryEdge -> - if (summaryEdge.from == calleeStartVertex) { - handleSummaryEdge(currentEdge, summaryEdge) - } else { - logger.trace { "Skipping unsuitable summary edge: $summaryEdge" } - } - } - } else { - // Save info about the call for summary edges that will be found later: - callerPathEdgeOf.getOrPut(calleeStartVertex) { hashSetOf() }.add(currentEdge) - - // Initialize analysis of callee: - run { - val newEdge = Edge(calleeStartVertex, calleeStartVertex) // loop - propagate(newEdge, Reason.CallToStart(currentEdge)) - } - - // Handle already-found summary edges: - for (exitVertex in summaryEdges[calleeStartVertex].orEmpty()) { - val summaryEdge = Edge(calleeStartVertex, exitVertex) - handleSummaryEdge(currentEdge, summaryEdge) - } - } - } - } - } - } else { - if (currentIsExit) { - // Propagate through the summary edge: - for (callerPathEdge in callerPathEdgeOf[startVertex].orEmpty()) { - handleSummaryEdge(currentEdge = callerPathEdge, summaryEdge = currentEdge) - } - - // Add new summary edge: - summaryEdges.getOrPut(startVertex) { hashSetOf() }.add(currentVertex) - } - - // Simple (sequential) propagation to the next instruction: - for (next in graph.successors(current)) { - val factsAtNext = flowSpace - .obtainSequentFlowFunction(current, next) - .compute(currentFact) - for (nextFact in factsAtNext) { - val nextVertex = Vertex(next, nextFact) - val newEdge = Edge(startVertex, nextVertex) - propagate(newEdge, Reason.Sequent(currentEdge)) - } - } - } - } - - private fun handleSummaryEdge( - currentEdge: Edge, - summaryEdge: Edge, - ) { - val (startVertex, currentVertex) = currentEdge - val caller = currentVertex.statement - for (returnSite in graph.successors(caller)) { - val (exit, exitFact) = summaryEdge.to - val finalFacts = flowSpace - .obtainExitToReturnSiteFlowFunction(caller, returnSite, exit) - .compute(exitFact) - for (returnSiteFact in finalFacts) { - val returnSiteVertex = Vertex(returnSite, returnSiteFact) - val newEdge = Edge(startVertex, returnSiteVertex) - propagate(newEdge, Reason.ThroughSummary(currentEdge, summaryEdge)) - } - } - } - - private fun getFinalFacts(): Map> { - val resultFacts: MutableMap> = hashMapOf() - for (edge in pathEdges) { - resultFacts.getOrPut(edge.to.statement) { hashSetOf() }.add(edge.to.fact) - } - return resultFacts - } - - override fun getIfdsResult(): IfdsResult { - val facts = getFinalFacts() - return IfdsResult(pathEdges, facts, reasons, zeroFact) - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt index 3f0c90206..03f73974b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt @@ -16,11 +16,7 @@ package org.jacodb.analysis.ifds -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow import org.jacodb.api.JcMethod -import java.util.concurrent.ConcurrentHashMap /** * A common interface for anything that should be remembered @@ -30,13 +26,6 @@ interface Summary { val method: JcMethod } -interface SummaryEdge : Summary { - val edge: Edge - - override val method: JcMethod - get() = edge.method -} - interface Vulnerability : Summary { val message: String val sink: Vertex @@ -45,59 +34,3 @@ interface Vulnerability : Summary { get() = sink.method } -/** - * Contains summaries for many methods and allows to update them and subscribe for them. - */ -interface SummaryStorage { - /** - * A list of all methods for which summaries are not empty. - */ - val knownMethods: List - - /** - * Adds [fact] to summary of its method. - */ - fun add(fact: T) - - /** - * @return a flow with all facts summarized for the given [method]. - * Already received facts, along with the facts that will be sent to this storage later, - * will be emitted to the returned flow. - */ - fun getFacts(method: JcMethod): Flow - - /** - * @return a list will all facts summarized for the given [method] so far. - */ - fun getCurrentFacts(method: JcMethod): List -} - -class SummaryStorageImpl : SummaryStorage { - private val summaries = ConcurrentHashMap>() - private val outFlows = ConcurrentHashMap>() - - override val knownMethods: List - get() = summaries.keys.toList() - - private fun getFlow(method: JcMethod): MutableSharedFlow { - return outFlows.computeIfAbsent(method) { - MutableSharedFlow(replay = Int.MAX_VALUE) - } - } - - override fun add(fact: T) { - val isNew = summaries.computeIfAbsent(fact.method) { ConcurrentHashMap.newKeySet() }.add(fact) - if (isNew) { - val flow = getFlow(fact.method) - check(flow.tryEmit(fact)) - } - } - - override fun getFacts(method: JcMethod): SharedFlow { - return getFlow(method) - } - - override fun getCurrentFacts(method: JcMethod): List { - return getFacts(method).replayCache - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt deleted file mode 100644 index 60a83d380..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/TraceGraph.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.ifds - -data class TraceGraph( - val sink: Vertex, - val sources: MutableSet>, - val edges: MutableMap, MutableSet>>, - val unresolvedCrossUnitCalls: Map, Set>>, -) { - /** - * Returns all traces from [sources] to [sink]. - */ - fun getAllTraces(): Sequence>> = sequence { - for (v in sources) { - yieldAll(getAllTraces(mutableListOf(v))) - } - } - - private fun getAllTraces( - trace: MutableList>, - ): Sequence>> = sequence { - val v = trace.last() - if (v == sink) { - yield(trace.toList()) // copy list - return@sequence - } - for (u in edges[v].orEmpty()) { - if (u !in trace) { - trace.add(u) - yieldAll(getAllTraces(trace)) - trace.removeLast() - } - } - } - - /** - * Merges [upGraph] into this graph. - */ - fun mergeWithUpGraph( - upGraph: TraceGraph, - entryPoints: Set>, - ) { - sources.addAll(upGraph.sources) - - for (edge in upGraph.edges) { - edges.getOrPut(edge.key) { hashSetOf() }.addAll(edge.value) - } - - edges.getOrPut(upGraph.sink) { hashSetOf() }.addAll(entryPoints) - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt deleted file mode 100644 index 605257f0d..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/UnitResolver.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.JcClassOrInterface -import org.jacodb.api.JcMethod -import org.jacodb.api.ext.packageName - -interface UnitType - -data class MethodUnit(val method: JcMethod) : UnitType { - override fun toString(): String { - return "MethodUnit(${method.name})" - } -} - -data class ClassUnit(val clazz: JcClassOrInterface) : UnitType { - override fun toString(): String { - return "ClassUnit(${clazz.simpleName})" - } -} - -data class PackageUnit(val packageName: String) : UnitType { - override fun toString(): String { - return "PackageUnit($packageName)" - } -} - -object UnknownUnit : UnitType { - override fun toString(): String = javaClass.simpleName -} - -object SingletonUnit : UnitType { - override fun toString(): String = javaClass.simpleName -} - -/** - * Sets a mapping from [JcMethod] to abstract domain [UnitType]. - * - * Therefore, it splits all methods into units, containing one or more method each - * (unit is a set of methods with same value of [UnitType] returned by [resolve]). - */ -fun interface UnitResolver { - - fun resolve(method: JcMethod): UnitType - - companion object { - fun getByName(name: String): UnitResolver = when (name) { - "method" -> MethodUnitResolver - "class" -> ClassUnitResolver(false) - "package" -> PackageUnitResolver - "singleton" -> SingletonUnitResolver - else -> error("Unknown unit resolver '$name'") - } - } -} - -val MethodUnitResolver = UnitResolver { method -> - MethodUnit(method) -} - -@Suppress("FunctionName") -fun ClassUnitResolver(includeNested: Boolean) = UnitResolver { method -> - val clazz = if (includeNested) { - generateSequence(method.enclosingClass) { it.outerClass }.last() - } else { - method.enclosingClass - } - ClassUnit(clazz) -} - -val PackageUnitResolver = UnitResolver { method -> - PackageUnit(method.enclosingClass.packageName) -} - -val SingletonUnitResolver = UnitResolver { _ -> - SingletonUnit -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt index ccd671aa4..20f0dd477 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt @@ -19,14 +19,11 @@ package org.jacodb.analysis.npe import org.jacodb.analysis.config.CallPositionToJcValueResolver import org.jacodb.analysis.config.FactAwareConditionEvaluator import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.ifds.Reason -import org.jacodb.analysis.taint.EdgeForOtherRunner import org.jacodb.analysis.taint.NewSummaryEdge import org.jacodb.analysis.taint.NewVulnerability import org.jacodb.analysis.taint.TaintEdge import org.jacodb.analysis.taint.TaintEvent import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintVertex import org.jacodb.analysis.taint.Tainted import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.api.analysis.JcApplicationGraph @@ -97,10 +94,4 @@ class NpeAnalyzer( } } - override fun handleCrossUnitCall( - caller: TaintVertex, - callee: TaintVertex, - ): List = buildList { - add(EdgeForOtherRunner(TaintEdge(callee, callee), Reason.CrossUnitCall(caller))) - } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt deleted file mode 100644 index 1b72e58ef..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeManager.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.npe - -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.analysis.ifds.UnknownUnit -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.TaintRunner -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph - -private val logger = mu.KotlinLogging.logger {} - -class NpeManager( - graph: JcApplicationGraph, - unitResolver: UnitResolver, -) : TaintManager(graph, unitResolver, useBidiRunner = false) { - - override fun newRunner( - unit: UnitType, - ): TaintRunner { - check(unit !in runnerForUnit) { "Runner for $unit already exists" } - - val analyzer = NpeAnalyzer(graph) - val runner = UniRunner( - graph = graph, - analyzer = analyzer, - manager = this@NpeManager, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - - runnerForUnit[unit] = runner - return runner - } - - override fun addStart(method: JcMethod) { - logger.info { "Adding start method: $method" } - val unit = unitResolver.resolve(method) - if (unit == UnknownUnit) return - methodsForUnit.getOrPut(unit) { hashSetOf() }.add(method) - // Note: DO NOT add deps here! - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt deleted file mode 100644 index 4101a14b8..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Sarif.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.sarif - -import io.github.detekt.sarif4k.ArtifactLocation -import io.github.detekt.sarif4k.CodeFlow -import io.github.detekt.sarif4k.Location -import io.github.detekt.sarif4k.LogicalLocation -import io.github.detekt.sarif4k.Message -import io.github.detekt.sarif4k.MultiformatMessageString -import io.github.detekt.sarif4k.PhysicalLocation -import io.github.detekt.sarif4k.Region -import io.github.detekt.sarif4k.Result -import io.github.detekt.sarif4k.Run -import io.github.detekt.sarif4k.SarifSchema210 -import io.github.detekt.sarif4k.ThreadFlow -import io.github.detekt.sarif4k.ThreadFlowLocation -import io.github.detekt.sarif4k.Tool -import io.github.detekt.sarif4k.ToolComponent -import io.github.detekt.sarif4k.Version -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.api.JcMethod -import org.jacodb.api.cfg.JcInst -import java.io.File - -private const val SARIF_SCHEMA = - "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json" -private const val JACODB_INFORMATION_URI = - "https://github.com/UnitTestBot/jacodb/blob/develop/jacodb-analysis/README.md" -private const val DEFAULT_PATH_COUNT = 3 - -fun sarifReportFromVulnerabilities( - vulnerabilities: List>, - maxPathsCount: Int = DEFAULT_PATH_COUNT, - isDeduplicate: Boolean = true, - sourceFileResolver: SourceFileResolver = SourceFileResolver { null }, -): SarifSchema210 { - return SarifSchema210( - schema = SARIF_SCHEMA, - version = Version.The210, - runs = listOf( - Run( - tool = Tool( - driver = ToolComponent( - name = "jacodb-analysis", - organization = "UnitTestBot", - version = "1.4.5", - informationURI = JACODB_INFORMATION_URI, - ) - ), - results = vulnerabilities.map { instance -> - Result( - ruleID = instance.description.ruleId, - message = Message( - text = instance.description.message - ), - level = instance.description.level, - locations = listOf(instToSarifLocation(instance.traceGraph.sink.statement, sourceFileResolver)), - codeFlows = instance.traceGraph - .getAllTraces() - .take(maxPathsCount) - .map { traceToSarifCodeFlow(it, sourceFileResolver, isDeduplicate) } - .toList(), - ) - } - ) - ) - ) -} - -private val JcMethod.fullyQualifiedName: String - get() = "${enclosingClass.name}#${name}" - -private fun instToSarifLocation(inst: JcInst, sourceFileResolver: SourceFileResolver): Location { - val sourceLocation = sourceFileResolver.resolve(inst) - ?: run { - val registeredLocation = inst.location.method.declaration.location - val classFile = inst.location.method.enclosingClass.name - .replace('.', '/') + ".class" - File(registeredLocation.path).resolve(classFile).path - } - return Location( - physicalLocation = PhysicalLocation( - artifactLocation = ArtifactLocation( - uri = sourceLocation - ), - region = Region( - startLine = inst.location.lineNumber.toLong() - ) - ), - logicalLocations = listOf( - LogicalLocation( - fullyQualifiedName = inst.location.method.fullyQualifiedName - ) - ) - ) -} - -private fun traceToSarifCodeFlow( - trace: List>, - sourceFileResolver: SourceFileResolver, - isDeduplicate: Boolean = true, -): CodeFlow { - return CodeFlow( - threadFlows = listOf( - ThreadFlow( - locations = trace.map { - ThreadFlowLocation( - location = instToSarifLocation(it.statement, sourceFileResolver), - state = mapOf( - "fact" to MultiformatMessageString( - text = it.fact.toString() - ) - ) - ) - }.let { - if (isDeduplicate) it.deduplicate() else it - } - ) - ) - ) -} - -private fun List.deduplicate(): List { - if (isEmpty()) return emptyList() - - return listOf(first()) + zipWithNext { a, b -> - val aLine = a.location!!.physicalLocation!!.region!!.startLine!! - val bLine = b.location!!.physicalLocation!!.region!!.startLine!! - if (aLine != bLine) { - b - } else { - null - } - }.filterNotNull() -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt deleted file mode 100644 index c30f15486..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/SourceFileResolver.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.sarif - -import org.jacodb.api.cfg.JcInst - -fun interface SourceFileResolver { - fun resolve(inst: JcInst): String? -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt deleted file mode 100644 index 6d83a5ac2..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/sarif/Vulnerability.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.sarif - -import io.github.detekt.sarif4k.Level -import org.jacodb.analysis.ifds.TraceGraph - -data class VulnerabilityInstance( - val traceGraph: TraceGraph, - val description: VulnerabilityDescription, -) - -data class VulnerabilityDescription( - val ruleId: String?, - val message: String?, - val level: Level = Level.Warning, -) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt deleted file mode 100644 index 7d2029b36..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Sarif.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.analysis.sarif.VulnerabilityDescription -import org.jacodb.analysis.sarif.VulnerabilityInstance - -fun TaintVulnerability.toSarif( - graph: TraceGraph, -): VulnerabilityInstance { - return VulnerabilityInstance( - graph, - VulnerabilityDescription( - ruleId = null, - message = rule?.ruleNote - ) - ) -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt index ae59345cb..797e97a67 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt @@ -79,12 +79,6 @@ class TaintAnalyzer( } } - override fun handleCrossUnitCall( - caller: TaintVertex, - callee: TaintVertex, - ): List = buildList { - add(EdgeForOtherRunner(TaintEdge(callee, callee), Reason.CrossUnitCall(caller))) - } } class BackwardTaintAnalyzer( @@ -106,11 +100,4 @@ class BackwardTaintAnalyzer( add(EdgeForOtherRunner(Edge(edge.to, edge.to), reason = Reason.External)) } } - - override fun handleCrossUnitCall( - caller: TaintVertex, - callee: TaintVertex, - ): List { - return emptyList() - } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt deleted file mode 100644 index dbc516663..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintBidiRunner.kt +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.taint - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import org.jacodb.analysis.ifds.ControlEvent -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.IfdsResult -import org.jacodb.analysis.ifds.Manager -import org.jacodb.analysis.ifds.QueueEmptinessChanged -import org.jacodb.analysis.ifds.Reason -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.api.JcMethod - -class TaintBidiRunner( - val manager: TaintManager, - val unitResolver: UnitResolver, - override val unit: UnitType, - newForwardRunner: (Manager) -> TaintRunner, - newBackwardRunner: (Manager) -> TaintRunner, -) : TaintRunner { - - @Volatile - private var forwardQueueIsEmpty: Boolean = false - - @Volatile - private var backwardQueueIsEmpty: Boolean = false - - private val forwardManager: Manager = - object : Manager { - override fun handleEvent(event: TaintEvent) { - when (event) { - is EdgeForOtherRunner -> { - if (unitResolver.resolve(event.edge.method) == unit) { - // Submit new edge directly to the backward runner: - backwardRunner.submitNewEdge(event.edge, event.reason) - } else { - // Submit new edge via the manager: - manager.handleEvent(event) - } - } - - else -> manager.handleEvent(event) - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - forwardQueueIsEmpty = event.isEmpty - val newEvent = QueueEmptinessChanged(event.runner, forwardQueueIsEmpty && backwardQueueIsEmpty) - manager.handleControlEvent(newEvent) - } - } - } - - override fun subscribeOnSummaryEdges( - method: JcMethod, - scope: CoroutineScope, - handler: (TaintEdge) -> Unit, - ) { - manager.subscribeOnSummaryEdges(method, scope, handler) - } - } - - private val backwardManager: Manager = - object : Manager { - override fun handleEvent(event: TaintEvent) { - when (event) { - is EdgeForOtherRunner -> { - check(unitResolver.resolve(event.edge.method) == unit) - // Submit new edge directly to the forward runner: - forwardRunner.submitNewEdge(event.edge, event.reason) - } - - else -> manager.handleEvent(event) - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - backwardQueueIsEmpty = event.isEmpty - val newEvent = QueueEmptinessChanged(event.runner, forwardQueueIsEmpty && backwardQueueIsEmpty) - manager.handleControlEvent(newEvent) - } - } - } - - override fun subscribeOnSummaryEdges( - method: JcMethod, - scope: CoroutineScope, - handler: (TaintEdge) -> Unit, - ) { - // TODO: ignore? - manager.subscribeOnSummaryEdges(method, scope, handler) - } - } - - val forwardRunner: TaintRunner = newForwardRunner(forwardManager) - val backwardRunner: TaintRunner = newBackwardRunner(backwardManager) - - init { - check(forwardRunner.unit == unit) - check(backwardRunner.unit == unit) - } - - override fun submitNewEdge(edge: Edge, reason: Reason) { - forwardRunner.submitNewEdge(edge, reason) - } - - override suspend fun run(startMethods: List) = coroutineScope { - val backwardRunnerJob = launch(start = CoroutineStart.LAZY) { backwardRunner.run(startMethods) } - val forwardRunnerJob = launch(start = CoroutineStart.LAZY) { forwardRunner.run(startMethods) } - - backwardRunnerJob.start() - forwardRunnerJob.start() - - backwardRunnerJob.join() - forwardRunnerJob.join() - } - - override fun getIfdsResult(): IfdsResult { - return forwardRunner.getIfdsResult() - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt deleted file mode 100644 index f81a1599c..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintManager.kt +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.taint - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.isActive -import kotlinx.coroutines.joinAll -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withTimeoutOrNull -import org.jacodb.analysis.graph.reversed -import org.jacodb.analysis.ifds.ControlEvent -import org.jacodb.analysis.ifds.IfdsResult -import org.jacodb.analysis.ifds.Manager -import org.jacodb.analysis.ifds.QueueEmptinessChanged -import org.jacodb.analysis.ifds.SummaryStorageImpl -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.analysis.ifds.UnknownUnit -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.analysis.util.getPathEdges -import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph -import java.util.concurrent.ConcurrentHashMap -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit -import kotlin.time.ExperimentalTime -import kotlin.time.TimeSource - -private val logger = mu.KotlinLogging.logger {} - -open class TaintManager( - protected val graph: JcApplicationGraph, - protected val unitResolver: UnitResolver, - private val useBidiRunner: Boolean = false, -) : Manager { - - protected val methodsForUnit: MutableMap> = hashMapOf() - protected val runnerForUnit: MutableMap = hashMapOf() - private val queueIsEmpty = ConcurrentHashMap() - - private val summaryEdgesStorage = SummaryStorageImpl() - private val vulnerabilitiesStorage = SummaryStorageImpl() - - private val stopRendezvous = Channel(Channel.RENDEZVOUS) - - protected open fun newRunner( - unit: UnitType, - ): TaintRunner { - check(unit !in runnerForUnit) { "Runner for $unit already exists" } - - logger.debug { "Creating a new runner for $unit" } - val runner = if (useBidiRunner) { - TaintBidiRunner( - manager = this@TaintManager, - unitResolver = unitResolver, - unit = unit, - { manager -> - val analyzer = TaintAnalyzer(graph) - UniRunner( - graph = graph, - analyzer = analyzer, - manager = manager, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - }, - { manager -> - val analyzer = BackwardTaintAnalyzer(graph) - UniRunner( - graph = graph.reversed, - analyzer = analyzer, - manager = manager, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - } - ) - } else { - val analyzer = TaintAnalyzer(graph) - UniRunner( - graph = graph, - analyzer = analyzer, - manager = this@TaintManager, - unitResolver = unitResolver, - unit = unit, - zeroFact = TaintZeroFact - ) - } - - runnerForUnit[unit] = runner - return runner - } - - private fun getAllCallees(method: JcMethod): Set { - val result: MutableSet = hashSetOf() - for (inst in method.flowGraph().instructions) { - result += graph.callees(inst) - } - return result - } - - protected open fun addStart(method: JcMethod) { - logger.info { "Adding start method: $method" } - val unit = unitResolver.resolve(method) - if (unit == UnknownUnit) return - val isNew = methodsForUnit.getOrPut(unit) { hashSetOf() }.add(method) - if (isNew) { - for (dep in getAllCallees(method)) { - addStart(dep) - } - } - } - - @JvmName("analyze") // needed for Java interop because of inline class (Duration) - @OptIn(ExperimentalTime::class) - fun analyze( - startMethods: List, - timeout: Duration = 3600.seconds, - ): List = runBlocking(Dispatchers.Default) { - val timeStart = TimeSource.Monotonic.markNow() - - // Add start methods: - for (method in startMethods) { - addStart(method) - } - - // Determine all units: - val allUnits = methodsForUnit.keys.toList() - logger.info { - "Starting analysis of ${ - methodsForUnit.values.sumOf { it.size } - } methods in ${allUnits.size} units" - } - - // Spawn runner jobs: - val allJobs = allUnits.map { unit -> - // Create the runner: - val runner = newRunner(unit) - - // Start the runner: - launch(start = CoroutineStart.LAZY) { - val methods = methodsForUnit[unit]!!.toList() - runner.run(methods) - } - } - - // Spawn progress job: - val progress = launch(Dispatchers.IO) { - while (isActive) { - delay(1.seconds) - logger.info { - "Progress: propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - } - } - - // Spawn stopper job: - val stopper = launch(Dispatchers.IO) { - stopRendezvous.receive() - logger.info { "Stopping all runners..." } - allJobs.forEach { it.cancel() } - } - - // Start all runner jobs: - val timeStartJobs = TimeSource.Monotonic.markNow() - allJobs.forEach { it.start() } - - // Await all runners: - withTimeoutOrNull(timeout) { - allJobs.joinAll() - } ?: run { - logger.info { "Timeout!" } - allJobs.forEach { it.cancel() } - allJobs.joinAll() - } - progress.cancelAndJoin() - stopper.cancelAndJoin() - logger.info { - "All ${allJobs.size} jobs completed in %.1f s".format( - timeStartJobs.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - - // Extract found vulnerabilities (sinks): - val foundVulnerabilities = vulnerabilitiesStorage.knownMethods - .flatMap { method -> - vulnerabilitiesStorage.getCurrentFacts(method) - } - if (logger.isDebugEnabled) { - logger.debug { "Total found ${foundVulnerabilities.size} vulnerabilities" } - for (vulnerability in foundVulnerabilities) { - logger.debug { "$vulnerability in ${vulnerability.method}" } - } - } - logger.info { "Total sinks: ${foundVulnerabilities.size}" } - logger.info { - "Total propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - logger.info { - "Analysis done in %.1f s".format( - timeStart.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - foundVulnerabilities - } - - override fun handleEvent(event: TaintEvent) { - when (event) { - is NewSummaryEdge -> { - summaryEdgesStorage.add(TaintSummaryEdge(event.edge)) - } - - is NewVulnerability -> { - vulnerabilitiesStorage.add(event.vulnerability) - } - - is EdgeForOtherRunner -> { - val method = event.edge.method - val unit = unitResolver.resolve(method) - val otherRunner = runnerForUnit[unit] ?: run { - // error("No runner for $unit") - logger.trace { "Ignoring event=$event for non-existing runner for unit=$unit" } - return - } - otherRunner.submitNewEdge(event.edge, event.reason) - } - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - queueIsEmpty[event.runner.unit] = event.isEmpty - if (event.isEmpty) { - if (runnerForUnit.keys.all { queueIsEmpty[it] == true }) { - logger.debug { "All runners are empty" } - stopRendezvous.trySend(Unit).getOrNull() - } - } - } - } - } - - override fun subscribeOnSummaryEdges( - method: JcMethod, - scope: CoroutineScope, - handler: (TaintEdge) -> Unit, - ) { - summaryEdgesStorage - .getFacts(method) - .onEach { handler(it.edge) } - .launchIn(scope) - } - - fun vulnerabilityTraceGraph(vulnerability: TaintVulnerability): TraceGraph { - val result = getIfdsResultForMethod(vulnerability.method) - val initialGraph = result.buildTraceGraph(vulnerability.sink) - val resultGraph = initialGraph.copy(unresolvedCrossUnitCalls = emptyMap()) - - val resolvedCrossUnitEdges = hashSetOf, Vertex>>() - val unresolvedCrossUnitCalls = initialGraph.unresolvedCrossUnitCalls.entries.toMutableList() - while (unresolvedCrossUnitCalls.isNotEmpty()) { - val (caller, callees) = unresolvedCrossUnitCalls.removeLast() - - val unresolvedCallees = hashSetOf>() - for (callee in callees) { - if (resolvedCrossUnitEdges.add(caller to callee)) { - unresolvedCallees.add(callee) - } - } - - if (unresolvedCallees.isEmpty()) continue - - val callerResult = getIfdsResultForMethod(caller.method) - val callerGraph = callerResult.buildTraceGraph(caller) - resultGraph.mergeWithUpGraph(callerGraph, unresolvedCallees) - unresolvedCrossUnitCalls += callerGraph.unresolvedCrossUnitCalls.entries - } - - return resultGraph - } - - private fun getIfdsResultForMethod(method: JcMethod): IfdsResult { - val unit = unitResolver.resolve(method) - val runner = runnerForUnit[unit] ?: error("No runner for $unit") - return runner.getIfdsResult() - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt index bb70b5349..abc24efe5 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt @@ -16,14 +16,9 @@ package org.jacodb.analysis.taint -import org.jacodb.analysis.ifds.SummaryEdge import org.jacodb.analysis.ifds.Vulnerability import org.jacodb.taint.configuration.TaintMethodSink -data class TaintSummaryEdge( - override val edge: TaintEdge, -) : SummaryEdge - data class TaintVulnerability( override val message: String, override val sink: TaintVertex, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt index 88be4cd3a..e06b16ce0 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt @@ -17,9 +17,7 @@ package org.jacodb.analysis.taint import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Runner import org.jacodb.analysis.ifds.Vertex typealias TaintVertex = Vertex typealias TaintEdge = Edge -typealias TaintRunner = Runner diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt deleted file mode 100644 index 85f1136f2..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Sarif.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.TraceGraph -import org.jacodb.analysis.sarif.VulnerabilityDescription -import org.jacodb.analysis.sarif.VulnerabilityInstance - -fun UnusedVariableVulnerability.toSarif(): VulnerabilityInstance { - return VulnerabilityInstance( - TraceGraph(sink, mutableSetOf(sink), mutableMapOf(), emptyMap()), - VulnerabilityDescription(ruleId = null, message = message) - ) -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt index 2acf1b730..a1db7757b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt @@ -18,7 +18,6 @@ package org.jacodb.analysis.unused import org.jacodb.analysis.ifds.Analyzer import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Vertex import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst @@ -40,7 +39,4 @@ class UnusedVariableAnalyzer( } } - override fun handleCrossUnitCall(caller: Vertex, callee: Vertex): List { - return emptyList() - } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt deleted file mode 100644 index ea3a99d01..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableManager.kt +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.unused - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.isActive -import kotlinx.coroutines.joinAll -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withTimeoutOrNull -import org.jacodb.analysis.ifds.ControlEvent -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Manager -import org.jacodb.analysis.ifds.QueueEmptinessChanged -import org.jacodb.analysis.ifds.Runner -import org.jacodb.analysis.ifds.SummaryStorageImpl -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.ifds.UnitType -import org.jacodb.analysis.ifds.UnknownUnit -import org.jacodb.analysis.ifds.Vertex -import org.jacodb.analysis.util.getPathEdges -import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.api.cfg.JcInst -import java.util.concurrent.ConcurrentHashMap -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit -import kotlin.time.ExperimentalTime -import kotlin.time.TimeSource - -private val logger = mu.KotlinLogging.logger {} - -class UnusedVariableManager( - private val graph: JcApplicationGraph, - private val unitResolver: UnitResolver, -) : Manager { - - private val methodsForUnit: MutableMap> = hashMapOf() - private val runnerForUnit: MutableMap> = hashMapOf() - private val queueIsEmpty = ConcurrentHashMap() - - private val summaryEdgesStorage = SummaryStorageImpl() - private val vulnerabilitiesStorage = SummaryStorageImpl() - - private val stopRendezvous = Channel(Channel.RENDEZVOUS) - - private fun newRunner( - unit: UnitType, - ): Runner { - check(unit !in runnerForUnit) { "Runner for $unit already exists" } - - logger.debug { "Creating a new runner for $unit" } - val analyzer = UnusedVariableAnalyzer(graph) - val runner = UniRunner( - graph = graph, - analyzer = analyzer, - manager = this@UnusedVariableManager, - unitResolver = unitResolver, - unit = unit, - zeroFact = UnusedVariableZeroFact - ) - - runnerForUnit[unit] = runner - return runner - } - - private fun getAllCallees(method: JcMethod): Set { - val result: MutableSet = hashSetOf() - for (inst in method.flowGraph().instructions) { - result += graph.callees(inst) - } - return result - } - - private fun addStart(method: JcMethod) { - logger.info { "Adding start method: $method" } - val unit = unitResolver.resolve(method) - if (unit == UnknownUnit) return - val isNew = methodsForUnit.getOrPut(unit) { hashSetOf() }.add(method) - if (isNew) { - for (dep in getAllCallees(method)) { - addStart(dep) - } - } - } - - @JvmName("analyze") // needed for Java interop because of inline class (Duration) - @OptIn(ExperimentalTime::class) - fun analyze( - startMethods: List, - timeout: Duration = 3600.seconds, - ): List = runBlocking { - val timeStart = TimeSource.Monotonic.markNow() - - // Add start methods: - for (method in startMethods) { - addStart(method) - } - - // Determine all units: - val allUnits = methodsForUnit.keys.toList() - logger.info { - "Starting analysis of ${ - methodsForUnit.values.sumOf { it.size } - } methods in ${allUnits.size} units" - } - - // Spawn runner jobs: - val allJobs = allUnits.map { unit -> - // Create the runner: - val runner = newRunner(unit) - - // Start the runner: - launch(start = CoroutineStart.LAZY) { - val methods = methodsForUnit[unit]!!.toList() - runner.run(methods) - } - } - - // Spawn progress job: - val progress = launch(Dispatchers.IO) { - while (isActive) { - delay(1.seconds) - logger.info { - "Progress: propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - } - } - - // Spawn stopper job: - val stopper = launch(Dispatchers.IO) { - stopRendezvous.receive() - logger.info { "Stopping all runners..." } - allJobs.forEach { it.cancel() } - } - - // Start all runner jobs: - val timeStartJobs = TimeSource.Monotonic.markNow() - allJobs.forEach { it.start() } - - // Await all runners: - withTimeoutOrNull(timeout) { - allJobs.joinAll() - } ?: run { - logger.info { "Timeout!" } - allJobs.forEach { it.cancel() } - allJobs.joinAll() - } - progress.cancelAndJoin() - stopper.cancelAndJoin() - logger.info { - "All ${allJobs.size} jobs completed in %.1f s".format( - timeStartJobs.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - - // Extract found vulnerabilities (sinks): - val foundVulnerabilities = allUnits.flatMap { unit -> - val runner = runnerForUnit[unit] ?: error("No runner for $unit") - val result = runner.getIfdsResult() - val allFacts = result.facts - - val used = hashMapOf() - for ((inst, facts) in allFacts) { - for (fact in facts) { - if (fact is UnusedVariable) { - used.putIfAbsent(fact.initStatement, false) - if (fact.variable.isUsedAt(inst)) { - used[fact.initStatement] = true - } - } - - } - } - used.filterValues { !it }.keys.map { - UnusedVariableVulnerability( - message = "Assigned value is unused", - sink = Vertex(it, UnusedVariableZeroFact) - ) - } - } - - if (logger.isDebugEnabled) { - logger.debug { "Total found ${foundVulnerabilities.size} vulnerabilities" } - for (vulnerability in foundVulnerabilities) { - logger.debug { "$vulnerability in ${vulnerability.method}" } - } - } - logger.info { "Total sinks: ${foundVulnerabilities.size}" } - logger.info { - "Total propagated ${ - runnerForUnit.values.sumOf { it.getPathEdges().size } - } path edges" - } - logger.info { - "Analysis done in %.1f s".format( - timeStart.elapsedNow().toDouble(DurationUnit.SECONDS) - ) - } - foundVulnerabilities - } - - override fun handleEvent(event: Event) { - when (event) { - is NewSummaryEdge -> { - summaryEdgesStorage.add(UnusedVariableSummaryEdge(event.edge)) - } - } - } - - override fun handleControlEvent(event: ControlEvent) { - when (event) { - is QueueEmptinessChanged -> { - queueIsEmpty[event.runner.unit] = event.isEmpty - if (event.isEmpty) { - if (runnerForUnit.keys.all { queueIsEmpty[it] == true }) { - logger.debug { "All runners are empty" } - stopRendezvous.trySend(Unit).getOrNull() - } - } - } - } - } - - override fun subscribeOnSummaryEdges( - method: JcMethod, - scope: CoroutineScope, - handler: (Edge) -> Unit, - ) { - summaryEdgesStorage - .getFacts(method) - .onEach { handler(it.edge) } - .launchIn(scope) - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt index 91d203504..b0af579e7 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt @@ -16,15 +16,9 @@ package org.jacodb.analysis.unused -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.SummaryEdge import org.jacodb.analysis.ifds.Vertex import org.jacodb.analysis.ifds.Vulnerability -data class UnusedVariableSummaryEdge( - override val edge: Edge, -) : SummaryEdge - data class UnusedVariableVulnerability( override val message: String, override val sink: Vertex, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/util/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/util/Utils.kt index 6b6bb924e..97f55df5c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/util/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/util/Utils.kt @@ -17,10 +17,6 @@ package org.jacodb.analysis.util import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Runner -import org.jacodb.analysis.ifds.UniRunner -import org.jacodb.analysis.taint.TaintBidiRunner import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.JcParameter @@ -40,12 +36,6 @@ fun JcClasspath.getArgumentsOf(method: JcMethod): List { return method.parameters.map { getArgument(it)!! } } -internal fun Runner<*>.getPathEdges(): Set> = when (this) { - is UniRunner<*, *> -> pathEdges - is TaintBidiRunner -> forwardRunner.getPathEdges() + backwardRunner.getPathEdges() - else -> error("Cannot extract pathEdges for $this") -} - fun AccessPath?.startsWith(other: AccessPath?): Boolean { if (this == null || other == null) { return false diff --git a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java index 022f7a1c6..2b36c5828 100644 --- a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java +++ b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java @@ -16,15 +16,9 @@ package org.jacodb.analysis.impl; -import kotlin.time.DurationUnit; import org.jacodb.analysis.graph.ApplicationGraphFactory; -import org.jacodb.analysis.ifds.UnitResolver; -import org.jacodb.analysis.ifds.UnitResolverKt; -import org.jacodb.analysis.taint.TaintManager; -import org.jacodb.api.JcClassOrInterface; import org.jacodb.api.JcClasspath; import org.jacodb.api.JcDatabase; -import org.jacodb.api.JcMethod; import org.jacodb.api.analysis.JcApplicationGraph; import org.jacodb.impl.JacoDB; import org.jacodb.impl.JcSettings; @@ -39,8 +33,6 @@ import java.util.List; import java.util.concurrent.ExecutionException; -import static kotlin.time.DurationKt.toDuration; - public class JavaAnalysisApiTest { private static JcClasspath classpath; @@ -51,19 +43,21 @@ public static void initClasspath() throws ExecutionException, InterruptedExcepti classpath = instance.asyncClasspath(LibrariesMixinKt.getAllClasspath()).get(); } - @Test - public void testJavaAnalysisApi() throws ExecutionException, InterruptedException { - JcClassOrInterface analyzedClass = classpath.findClassOrNull("org.jacodb.testing.analysis.NpeExamples"); - Assertions.assertNotNull(analyzedClass); - - List methodsToAnalyze = analyzedClass.getDeclaredMethods(); - JcApplicationGraph applicationGraph = ApplicationGraphFactory - .newApplicationGraphForAnalysisAsync(classpath, null) - .get(); - UnitResolver unitResolver = UnitResolverKt.getMethodUnitResolver(); - TaintManager manager = new TaintManager(applicationGraph, unitResolver, false); - manager.analyze(methodsToAnalyze, toDuration(30, DurationUnit.SECONDS)); - } +// TODO: fix test +// +// @Test +// public void testJavaAnalysisApi() throws ExecutionException, InterruptedException { +// JcClassOrInterface analyzedClass = classpath.findClassOrNull("org.jacodb.testing.analysis.NpeExamples"); +// Assertions.assertNotNull(analyzedClass); +// +// List methodsToAnalyze = analyzedClass.getDeclaredMethods(); +// JcApplicationGraph applicationGraph = ApplicationGraphFactory +// .newApplicationGraphForAnalysisAsync(classpath, null) +// .get(); +// UnitResolver unitResolver = UnitResolverKt.getMethodUnitResolver(); +// TaintManager manager = new TaintManager(applicationGraph, unitResolver, false); +// manager.analyze(methodsToAnalyze, toDuration(30, DurationUnit.SECONDS)); +// } @Test public void testCustomBannedPackagesApi() throws ExecutionException, InterruptedException { @@ -71,8 +65,8 @@ public void testCustomBannedPackagesApi() throws ExecutionException, Interrupted bannedPackages.add("my.package.that.wont.be.analyzed"); JcApplicationGraph customGraph = ApplicationGraphFactory - .newApplicationGraphForAnalysisAsync(classpath, bannedPackages) - .get(); + .newApplicationGraphForAnalysisAsync(classpath, bannedPackages) + .get(); Assertions.assertNotNull(customGraph); } } diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt index 033b639c1..65adc5f51 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt @@ -19,7 +19,6 @@ package org.jacodb.analysis.impl import juliet.support.AbstractTestCase import kotlinx.coroutines.runBlocking import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.graph.newApplicationGraphForAnalysis import org.jacodb.analysis.ifds.Vulnerability import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod From f381663e2a8b98f548665a6bac8c43aa042baf68 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 10:40:28 +0300 Subject: [PATCH 30/64] [ifds] wip: remove Reason --- .../kotlin/org/jacodb/analysis/ifds/Reason.kt | 21 ------------------- .../jacodb/analysis/taint/TaintAnalyzers.kt | 3 +-- .../org/jacodb/analysis/taint/TaintEvents.kt | 3 --- 3 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt deleted file mode 100644 index 1ee31a85c..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Reason.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.ifds - -sealed interface Reason { - object External : Reason -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt index 797e97a67..4858d9505 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt @@ -20,7 +20,6 @@ import org.jacodb.analysis.config.CallPositionToJcValueResolver import org.jacodb.analysis.config.FactAwareConditionEvaluator import org.jacodb.analysis.ifds.Analyzer import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Reason import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr @@ -97,7 +96,7 @@ class BackwardTaintAnalyzer( edge: TaintEdge, ): List = buildList { if (isExitPoint(edge.to.statement)) { - add(EdgeForOtherRunner(Edge(edge.to, edge.to), reason = Reason.External)) + add(EdgeForOtherRunner(Edge(edge.to, edge.to))) } } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt index ce1e9c8dc..256070f9e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt @@ -16,8 +16,6 @@ package org.jacodb.analysis.taint -import org.jacodb.analysis.ifds.Reason - sealed interface TaintEvent data class NewSummaryEdge( @@ -30,7 +28,6 @@ data class NewVulnerability( data class EdgeForOtherRunner( val edge: TaintEdge, - val reason: Reason ) : TaintEvent { init { // TODO: remove this check From cc25fe588e9fdc1eec6f1623326cbbf72e22b985 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 10:54:15 +0300 Subject: [PATCH 31/64] [ifds] wip: remove old Edge & Vertex, rename stmt -> statement --- .../kotlin/org/jacodb/ifds/ChunkResolver.kt | 20 ++++++------ .../org/jacodb/ifds/actors/RunnerStorage.kt | 2 +- .../kotlin/org/jacodb/ifds/domain/Vertex.kt | 4 +-- .../org/jacodb/analysis/ifds/Analyzer.kt | 5 ++- .../kotlin/org/jacodb/analysis/ifds/Edge.kt | 31 ------------------- .../org/jacodb/analysis/ifds/Summary.kt | 6 ++-- .../kotlin/org/jacodb/analysis/ifds/Vertex.kt | 28 ----------------- .../org/jacodb/analysis/npe/NpeAnalyzers.kt | 15 ++++----- .../jacodb/analysis/taint/TaintAnalyzers.kt | 7 +++-- .../kotlin/org/jacodb/analysis/taint/Types.kt | 10 +++--- .../analysis/unused/UnusedVariableAnalyzer.kt | 4 +-- .../analysis/unused/UnusedVariableEvents.kt | 5 +-- .../unused/UnusedVariableSummaries.kt | 5 +-- .../kotlin/org/jacodb/ifds/DefaultAnalyzer.kt | 8 ++--- .../kotlin/org/jacodb/ifds/FunctionWrapper.kt | 16 +++------- .../org/jacodb/ifds/IndirectionHandler.kt | 2 +- .../kotlin/org/jacodb/ifds/npe/Context.kt | 3 +- .../kotlin/org/jacodb/ifds/npe/Results.kt | 3 +- .../kotlin/org/jacodb/ifds/sarif/Sarif.kt | 4 +-- .../kotlin/org/jacodb/ifds/taint/Context.kt | 5 ++- .../kotlin/org/jacodb/ifds/taint/Results.kt | 3 +- .../kotlin/org/jacodb/ifds/unused/Context.kt | 3 +- .../kotlin/org/jacodb/ifds/unused/Results.kt | 3 +- .../jacodb/ifds/unused/SystemExtensions.kt | 2 +- 24 files changed, 67 insertions(+), 127 deletions(-) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt index 50fabe641..0aa6a8852 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt @@ -51,22 +51,22 @@ class DefaultChunkResolver( when (message) { is EdgeMessage<*, *> -> { message as EdgeMessage - chunkStrategy.chunkByStmt(message.edge.to.stmt) + chunkStrategy.chunkByStmt(message.edge.to.statement) } is NotificationOnEnd<*, *> -> { message as NotificationOnEnd - chunkStrategy.chunkByStmt(message.edge.to.stmt) + chunkStrategy.chunkByStmt(message.edge.to.statement) } is NotificationOnStart<*, *> -> { message as NotificationOnStart - chunkStrategy.chunkByStmt(message.edge.to.stmt) + chunkStrategy.chunkByStmt(message.edge.to.statement) } is ResolvedCall<*, *, *> -> { message as ResolvedCall - chunkStrategy.chunkByStmt(message.edge.to.stmt) + chunkStrategy.chunkByStmt(message.edge.to.statement) } else -> { @@ -79,7 +79,7 @@ class DefaultChunkResolver( when (message) { is UnresolvedCall<*, *> -> { message as UnresolvedCall - chunkStrategy.chunkByStmt(message.edge.to.stmt) + chunkStrategy.chunkByStmt(message.edge.to.statement) } else -> { @@ -92,17 +92,17 @@ class DefaultChunkResolver( when (message) { is NewEdge<*, *> -> { message as NewEdge - chunkStrategy.chunkByStmt(message.edge.to.stmt) + chunkStrategy.chunkByStmt(message.edge.to.statement) } is NewResult<*, *> -> { message as NewResult - chunkStrategy.chunkByStmt(message.result.vertex.stmt) + chunkStrategy.chunkByStmt(message.result.vertex.statement) } is NewSummaryEdge<*, *> -> { message as NewSummaryEdge - chunkStrategy.chunkByStmt(message.edge.to.stmt) + chunkStrategy.chunkByStmt(message.edge.to.statement) } is ObtainData<*, *, *> -> { @@ -112,12 +112,12 @@ class DefaultChunkResolver( is SubscriptionOnEnd<*, *> -> { message as SubscriptionOnEnd - chunkStrategy.chunkByStmt(message.endVertex.stmt) + chunkStrategy.chunkByStmt(message.endVertex.statement) } is SubscriptionOnStart<*, *> -> { message as SubscriptionOnStart - chunkStrategy.chunkByStmt(message.startVertex.stmt) + chunkStrategy.chunkByStmt(message.startVertex.statement) } } } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt index 775d4b97d..a8bfa9cc0 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt @@ -136,7 +136,7 @@ class RunnerStorage( message as ObtainData> val data = IfdsComputationData( edges.groupByTo(hashMapOf()) { it.to }, - edges.groupByTo(hashMapOf(), { it.to.stmt }) { it.to.fact }, + edges.groupByTo(hashMapOf(), { it.to.statement }) { it.to.fact }, reasons.toMap(hashMapOf()), foundResults.toHashSet() ) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt index dcf45864b..1d7a5146b 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt @@ -16,7 +16,7 @@ package org.jacodb.ifds.domain -data class Vertex( - val stmt: Stmt, +data class Vertex( + val statement: Stmt, val fact: Fact, ) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt index 158c80c67..a362f70ab 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt @@ -16,10 +16,13 @@ package org.jacodb.analysis.ifds +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Edge + interface Analyzer { val flowFunctions: FlowFunctions fun handleNewEdge( - edge: Edge, + edge: Edge, ): List } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt deleted file mode 100644 index 7492be3ea..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Edge.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.JcMethod - -data class Edge( - val from: Vertex, - val to: Vertex, -) { - init { - require(from.method == to.method) - } - - val method: JcMethod - get() = from.method -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt index 03f73974b..e792ca3a2 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt @@ -17,6 +17,8 @@ package org.jacodb.analysis.ifds import org.jacodb.api.JcMethod +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Vertex /** * A common interface for anything that should be remembered @@ -28,9 +30,9 @@ interface Summary { interface Vulnerability : Summary { val message: String - val sink: Vertex + val sink: Vertex override val method: JcMethod - get() = sink.method + get() = sink.statement.location.method } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt deleted file mode 100644 index df82fb813..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Vertex.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.JcMethod -import org.jacodb.api.cfg.JcInst - -data class Vertex( - val statement: JcInst, - val fact: Fact, -) { - val method: JcMethod - get() = statement.location.method -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt index 20f0dd477..35ab46ad6 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt @@ -21,11 +21,11 @@ import org.jacodb.analysis.config.FactAwareConditionEvaluator import org.jacodb.analysis.ifds.Analyzer import org.jacodb.analysis.taint.NewSummaryEdge import org.jacodb.analysis.taint.NewVulnerability +import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.analysis.taint.TaintEdge import org.jacodb.analysis.taint.TaintEvent -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.Tainted import org.jacodb.analysis.taint.TaintVulnerability +import org.jacodb.analysis.taint.Tainted import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr @@ -57,8 +57,9 @@ class NpeAnalyzer( add(NewSummaryEdge(edge)) } - if (edge.to.fact is Tainted && edge.to.fact.mark == TaintMark.NULLNESS) { - if (edge.to.fact.variable.isDereferencedAt(edge.to.statement)) { + val fact = edge.to.fact + if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { + if (fact.variable.isDereferencedAt(edge.to.statement)) { val message = "NPE" // TODO val vulnerability = TaintVulnerability(message, sink = edge.to) logger.info { "Found sink=${vulnerability.sink} in ${vulnerability.method}" } @@ -74,18 +75,18 @@ class NpeAnalyzer( // TODO: not always we want to skip sinks on Zero facts. // Some rules might have ConstantTrue or just true (when evaluated with Zero fact) condition. - if (edge.to.fact !is Tainted) { + if (fact !is Tainted) { return@run } // Determine whether 'edge.to' is a sink via config: val conditionEvaluator = FactAwareConditionEvaluator( - edge.to.fact, + fact, CallPositionToJcValueResolver(edge.to.statement), ) for (item in config.filterIsInstance()) { if (item.condition.accept(conditionEvaluator)) { - logger.trace { "Found sink at ${edge.to} in ${edge.method} on $item" } + logger.trace { "Found sink at ${edge.to} in ${edge.from.statement.location.method} on $item" } val message = item.ruleNote val vulnerability = TaintVulnerability(message, sink = edge.to, rule = item) add(NewVulnerability(vulnerability)) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt index 4858d9505..5004907ee 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt @@ -19,10 +19,10 @@ package org.jacodb.analysis.taint import org.jacodb.analysis.config.CallPositionToJcValueResolver import org.jacodb.analysis.config.FactAwareConditionEvaluator import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.ifds.Edge import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.ifds.domain.Edge import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.taint.configuration.TaintMethodSink @@ -58,13 +58,14 @@ class TaintAnalyzer( // TODO: not always we want to skip sinks on Zero facts. // Some rules might have ConstantTrue or just true (when evaluated with Zero fact) condition. - if (edge.to.fact !is Tainted) { + val fact = edge.to.fact + if (fact !is Tainted) { return@run } // Determine whether 'edge.to' is a sink via config: val conditionEvaluator = FactAwareConditionEvaluator( - edge.to.fact, + fact, CallPositionToJcValueResolver(edge.to.statement), ) for (item in config.filterIsInstance()) { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt index e06b16ce0..0614ec91f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt @@ -16,8 +16,10 @@ package org.jacodb.analysis.taint -import org.jacodb.analysis.ifds.Edge -import org.jacodb.analysis.ifds.Vertex +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Vertex -typealias TaintVertex = Vertex -typealias TaintEdge = Edge + +typealias TaintVertex = Vertex +typealias TaintEdge = Edge diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt index a1db7757b..1f1425c6b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt @@ -17,9 +17,9 @@ package org.jacodb.analysis.unused import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.ifds.Edge import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Edge class UnusedVariableAnalyzer( private val graph: JcApplicationGraph, @@ -33,7 +33,7 @@ class UnusedVariableAnalyzer( return statement in graph.exitPoints(statement.location.method) } - override fun handleNewEdge(edge: Edge): List = buildList { + override fun handleNewEdge(edge: Edge): List = buildList { if (isExitPoint(edge.to.statement)) { add(NewSummaryEdge(edge)) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt index 7073277dd..f9def48e4 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt @@ -16,10 +16,11 @@ package org.jacodb.analysis.unused -import org.jacodb.analysis.ifds.Edge +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Edge sealed interface Event data class NewSummaryEdge( - val edge: Edge, + val edge: Edge, ) : Event diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt index b0af579e7..c5cf7c1f5 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt @@ -16,10 +16,11 @@ package org.jacodb.analysis.unused -import org.jacodb.analysis.ifds.Vertex import org.jacodb.analysis.ifds.Vulnerability +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Vertex data class UnusedVariableVulnerability( override val message: String, - override val sink: Vertex, + override val sink: Vertex, ) : Vulnerability diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt index dfc3c38d2..f3906e0ac 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt @@ -64,7 +64,7 @@ class DefaultAnalyzer( } private fun TaintFlowScope.processEdge(edge: Edge) { - val toStmt = edge.to.stmt + val toStmt = edge.to.statement val method = applicationGraph.methodOf(toStmt) val callExpr = toStmt.callExpr @@ -80,7 +80,7 @@ class DefaultAnalyzer( val callMessage = UnresolvedCall(runnerId, edge) add(callMessage) - val successors = applicationGraph.successors(edge.to.stmt) + val successors = applicationGraph.successors(edge.to.statement) flowFunctions.run { for (successor in successors) { @@ -90,7 +90,7 @@ class DefaultAnalyzer( } private fun TaintFlowScope.processSequent(edge: Edge) { - val successors = applicationGraph.successors(edge.to.stmt) + val successors = applicationGraph.successors(edge.to.statement) flowFunctions.run { for (successor in successors) { @@ -114,7 +114,7 @@ class DefaultAnalyzer( private fun TaintFlowScope.processNotificationOnStart(message: NotificationOnStart) { - val successors = applicationGraph.successors(message.data.to.stmt) + val successors = applicationGraph.successors(message.data.to.statement) flowFunctions.run { for (successor in successors) { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt index c3a919308..ec80eaaef 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt @@ -38,7 +38,7 @@ class JcFlowFunctionsAdapter( override fun FlowScope.sequent(next: JcInst) = jcFlowFunctions - .obtainSequentFlowFunction(edge.to.stmt, next) + .obtainSequentFlowFunction(edge.to.statement, next) .compute(edge.to.fact) .forEach { newFact -> val newEdge = Edge(edge.from, Vertex(next, newFact)) @@ -47,7 +47,7 @@ class JcFlowFunctionsAdapter( override fun FlowScope.callToReturn(returnSite: JcInst) = jcFlowFunctions - .obtainCallToReturnSiteFlowFunction(edge.to.stmt, returnSite) + .obtainCallToReturnSiteFlowFunction(edge.to.statement, returnSite) .compute(edge.to.fact) .forEach { newFact -> val newEdge = Edge(edge.from, Vertex(returnSite, newFact)) @@ -56,7 +56,7 @@ class JcFlowFunctionsAdapter( override fun FlowScope.callToStart(calleeStart: JcInst) = jcFlowFunctions - .obtainCallToStartFlowFunction(edge.to.stmt, calleeStart) + .obtainCallToStartFlowFunction(edge.to.statement, calleeStart) .compute(edge.to.fact) .forEach { newFact -> val vertex = Vertex(calleeStart, newFact) @@ -72,7 +72,7 @@ class JcFlowFunctionsAdapter( callerEdge: Edge, returnSite: JcInst, ) = jcFlowFunctions - .obtainExitToReturnSiteFlowFunction(callerEdge.to.stmt, returnSite, edge.to.stmt) + .obtainExitToReturnSiteFlowFunction(callerEdge.to.statement, returnSite, edge.to.statement) .compute(edge.to.fact) .forEach { newFact -> val newEdge = Edge(callerEdge.from, Vertex(returnSite, newFact)) @@ -87,15 +87,9 @@ class JcFlowFunctionsAdapter( val edge = NewEdge(runnerId, newEdge, reason) add(edge) - val jcEvents = jcAnalyzer.handleNewEdge(newEdge.toJcEdge()) + val jcEvents = jcAnalyzer.handleNewEdge(newEdge) for (event in jcEvents) { jcEventProcessor(event) } } } - -private fun Vertex.toJcVertex() = org.jacodb.analysis.ifds.Vertex(stmt, fact) -private fun Edge.toJcEdge() = org.jacodb.analysis.ifds.Edge(from.toJcVertex(), to.toJcVertex()) - -fun org.jacodb.analysis.ifds.Vertex.toVertex() = Vertex(statement, fact) -fun org.jacodb.analysis.ifds.Edge.toEdge() = Edge(from.toVertex(), to.toVertex()) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt index 1b2e89ef4..e281e8382 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt @@ -47,7 +47,7 @@ class IndirectionHandler( @Suppress("UNCHECKED_CAST") message as? UnresolvedCall ?: return - val node = message.edge.to.stmt + val node = message.edge.to.statement val callees = (node.callExpr?.let { sequenceOf(it.method.method) } ?: emptySequence()) .filterNot { callee -> diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt index 25b8267e5..8ceaa05c2 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -29,7 +29,6 @@ import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext import org.jacodb.ifds.messages.NewResult import org.jacodb.ifds.messages.NewSummaryEdge -import org.jacodb.ifds.toEdge fun npeIfdsContext( cp: JcClasspath, @@ -58,7 +57,7 @@ fun npeIfdsContext( } is org.jacodb.analysis.taint.NewSummaryEdge -> { - val summaryEdge = NewSummaryEdge(runnerId, event.edge.toEdge()) + val summaryEdge = NewSummaryEdge(runnerId, event.edge) add(summaryEdge) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt index fe7dd12a8..de4c78f43 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt @@ -20,12 +20,11 @@ import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.toVertex import org.jacodb.ifds.result.IfdsResult data class NpeVulnerability( val vulnerability: TaintVulnerability, ) : IfdsResult { override val vertex: Vertex - get() = vulnerability.sink.toVertex() + get() = vulnerability.sink } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt index db71f2e34..82e1acd5d 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt @@ -69,7 +69,7 @@ fun sarifReportFromVulnerabilities( text = instance.description.message ), level = instance.description.level, - locations = listOf(instToSarifLocation(instance.traceGraph.sink.stmt, sourceFileResolver)), + locations = listOf(instToSarifLocation(instance.traceGraph.sink.statement, sourceFileResolver)), codeFlows = instance.traceGraph .getAllTraces() .take(maxPathsCount) @@ -120,7 +120,7 @@ private fun traceToSarifCodeFlow( ThreadFlow( locations = trace.map { ThreadFlowLocation( - location = instToSarifLocation(it.stmt, sourceFileResolver), + location = instToSarifLocation(it.statement, sourceFileResolver), state = mapOf( "fact" to MultiformatMessageString( text = it.fact.toString() diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt index c07fc2d8a..0c216d448 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -31,7 +31,6 @@ import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.toEdge import org.jacodb.ifds.messages.NewEdge as IfdsNewEdge import org.jacodb.ifds.messages.NewResult as IfdsNewResult import org.jacodb.ifds.messages.NewSummaryEdge as IfdsNewSummaryEdge @@ -72,7 +71,7 @@ fun taintIfdsContext( val edgeForOtherRunner = IfdsNewEdge( complementRunner(runnerId), - event.edge.toEdge(), + event.edge, Reason.FromOtherRunner(edge, runnerId) ) add(edgeForOtherRunner) @@ -80,7 +79,7 @@ fun taintIfdsContext( } is NewSummaryEdge -> { - val summaryEdge = IfdsNewSummaryEdge(runnerId, event.edge.toEdge()) + val summaryEdge = IfdsNewSummaryEdge(runnerId, event.edge) add(summaryEdge) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt index d8a82ed7c..625fad22f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt @@ -20,12 +20,11 @@ import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.IfdsResult -import org.jacodb.ifds.toVertex import org.jacodb.analysis.taint.TaintVulnerability as JcTaintVulnerability data class TaintVulnerability( val vulnerability: JcTaintVulnerability, ) : IfdsResult { override val vertex: Vertex - get() = vulnerability.sink.toVertex() + get() = vulnerability.sink } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt index bd1c6de35..6ee012cee 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt @@ -25,7 +25,6 @@ import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext -import org.jacodb.ifds.toEdge fun unusedIfdsContext( cp: JcClasspath, @@ -50,7 +49,7 @@ fun unusedIfdsContext( ) { event -> when (event) { is org.jacodb.analysis.unused.NewSummaryEdge -> { - val edge = org.jacodb.ifds.messages.NewSummaryEdge(runnerId, event.edge.toEdge()) + val edge = org.jacodb.ifds.messages.NewSummaryEdge(runnerId, event.edge) add(edge) } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt index 46200e2c7..2dad2a9ee 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt @@ -21,11 +21,10 @@ import org.jacodb.analysis.unused.UnusedVariableVulnerability import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.IfdsResult -import org.jacodb.ifds.toVertex data class UnusedVulnerability( val vulnerability: UnusedVariableVulnerability, ) : IfdsResult { override val vertex: Vertex - get() = vulnerability.sink.toVertex() + get() = vulnerability.sink } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt index 9bb44a39c..3daa4ce82 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -70,7 +70,7 @@ suspend fun ActorSystem.collectUnusedResult(): List Date: Tue, 14 May 2024 11:36:16 +0300 Subject: [PATCH 32/64] [ifds] wip: rename JcFlowScope --- .../kotlin/org/jacodb/ifds/domain/FlowScope.kt | 8 ++++---- .../kotlin/org/jacodb/ifds/DefaultAnalyzer.kt | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt index 50a0ce862..cb0004934 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt @@ -22,11 +22,11 @@ class FlowScope( val edge: Edge, private val messages: MutableList, ) { - fun add(message: RunnerMessage) { - messages.add(message) + fun add(newMessage: RunnerMessage) { + messages.add(newMessage) } - fun addAll(messages: Collection) { - this.messages.addAll(messages) + fun addAll(newMessages: Collection) { + messages.addAll(newMessages) } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt index f3906e0ac..6d6f43601 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt @@ -32,7 +32,7 @@ import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr -typealias TaintFlowScope = FlowScope +typealias JcFlowScope = FlowScope class DefaultAnalyzer( private val applicationGraph: JcApplicationGraph, @@ -42,18 +42,18 @@ class DefaultAnalyzer( override fun step(message: AnalyzerMessage): Collection = buildList { when (message) { is EdgeMessage -> { - val scope = TaintFlowScope(message.edge, this) + val scope = JcFlowScope(message.edge, this) scope.processEdge(message.edge) } is ResolvedCall -> { - val scope = TaintFlowScope(message.edge, this) + val scope = JcFlowScope(message.edge, this) @Suppress("UNCHECKED_CAST") scope.processResolvedCall(message as ResolvedCall) } is NotificationOnStart -> { - val scope = TaintFlowScope(message.edge, this) + val scope = JcFlowScope(message.edge, this) scope.processNotificationOnStart(message) } @@ -63,7 +63,7 @@ class DefaultAnalyzer( } } - private fun TaintFlowScope.processEdge(edge: Edge) { + private fun JcFlowScope.processEdge(edge: Edge) { val toStmt = edge.to.statement val method = applicationGraph.methodOf(toStmt) @@ -76,7 +76,7 @@ class DefaultAnalyzer( } } - private fun TaintFlowScope.processCall(edge: Edge) { + private fun JcFlowScope.processCall(edge: Edge) { val callMessage = UnresolvedCall(runnerId, edge) add(callMessage) @@ -89,7 +89,7 @@ class DefaultAnalyzer( } } - private fun TaintFlowScope.processSequent(edge: Edge) { + private fun JcFlowScope.processSequent(edge: Edge) { val successors = applicationGraph.successors(edge.to.statement) flowFunctions.run { @@ -100,7 +100,7 @@ class DefaultAnalyzer( } - private fun TaintFlowScope.processResolvedCall( + private fun JcFlowScope.processResolvedCall( resolvedCall: ResolvedCall, ) { val entryPoints = applicationGraph.entryPoints(resolvedCall.method) @@ -113,7 +113,7 @@ class DefaultAnalyzer( } - private fun TaintFlowScope.processNotificationOnStart(message: NotificationOnStart) { + private fun JcFlowScope.processNotificationOnStart(message: NotificationOnStart) { val successors = applicationGraph.successors(message.data.to.statement) flowFunctions.run { From 788fbd1c3259cdd2065946c9c9aa8ee0cf329c06 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 11:57:11 +0300 Subject: [PATCH 33/64] [ifds] wip: draft --- .../org/jacodb/ifds/actors/ChunkManager.kt | 2 +- .../org/jacodb/ifds/actors/RunnerStorage.kt | 30 +++++++++---------- .../org/jacodb/analysis/npe/NpeAnalyzers.kt | 4 +-- .../jacodb/analysis/taint/TaintAnalyzers.kt | 3 +- .../org/jacodb/analysis/taint/TaintEvents.kt | 2 ++ .../jacodb/analysis/taint/TaintSummaries.kt | 26 ---------------- .../unused/UnusedVariableSummaries.kt | 26 ---------------- .../kotlin/org/jacodb/ifds/npe/Context.kt | 9 +++++- .../kotlin/org/jacodb/ifds/npe/Results.kt | 9 ++++-- .../org/jacodb/ifds/npe/SystemExtensions.kt | 6 ++-- .../org/jacodb/ifds/sarif/Vulnerability.kt | 4 +-- .../kotlin/org/jacodb/ifds/taint/Context.kt | 2 +- .../kotlin/org/jacodb/ifds/taint/Results.kt | 10 ++++--- .../org/jacodb/ifds/taint/SystemExtensions.kt | 4 +-- .../kotlin/org/jacodb/ifds/unused/Results.kt | 6 ++-- .../jacodb/ifds/unused/SystemExtensions.kt | 5 ++-- .../jacodb/analysis/impl/BaseAnalysisTest.kt | 3 +- .../org/jacodb/analysis/impl/IfdsNpeTest.kt | 4 +-- .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 4 +-- .../jacodb/analysis/impl/IfdsUnusedTest.kt | 4 +-- 20 files changed, 62 insertions(+), 101 deletions(-) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt index 66da1d0a4..bfd8f4d51 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt @@ -37,7 +37,7 @@ class ChunkManager( private val routerFactory = messageKeyRouter( ifdsContext::runnerIdByMessage ) { runnerId -> - Runner(this@ActorContext.self, ifdsContext, chunk, runnerId) + Runner(this@ActorContext.self, ifdsContext, chunk, runnerId) } private val router = spawn( diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt index a8bfa9cc0..efd7c3045 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt @@ -42,15 +42,15 @@ class RunnerStorage( private val parent: ActorRef, private val runnerId: RunnerId, ) : Actor { - data class SubscriptionData( + data class SavedSubscription( val edge: Edge, val subscriber: RunnerId, ) private val startSubscribers = - HashMap, HashSet>>() + HashMap, HashSet>>() private val endSubscribers = - HashMap, HashSet>>() + HashMap, HashSet>>() private val edges = hashSetOf>() private val reasons = hashMapOf, HashSet>>() @@ -103,26 +103,26 @@ class RunnerStorage( @Suppress("UNCHECKED_CAST") message as SubscriptionOnStart - val subscriptionData = SubscriptionData(message.data, message.subscriber) + val savedSubscription = SavedSubscription(message.data, message.subscriber) - sendStartNotificationsOnExistingSummaryEdges(message.startVertex, subscriptionData) + sendStartNotificationsOnExistingSummaryEdges(message.startVertex, savedSubscription) startSubscribers .computeIfAbsent(message.startVertex) { hashSetOf() } - .add(subscriptionData) + .add(savedSubscription) } is SubscriptionOnEnd<*, *> -> { @Suppress("UNCHECKED_CAST") message as SubscriptionOnEnd - val subscriptionData = SubscriptionData(message.data, message.subscriber) + val savedSubscription = SavedSubscription(message.data, message.subscriber) - sendEndNotificationsOnExistingSummaryEdges(message.endVertex, subscriptionData) + sendEndNotificationsOnExistingSummaryEdges(message.endVertex, savedSubscription) endSubscribers .computeIfAbsent(message.endVertex) { hashSetOf() } - .add(subscriptionData) + .add(savedSubscription) } is NewResult<*, *> -> { @@ -147,15 +147,15 @@ class RunnerStorage( private suspend fun sendStartNotificationsOnExistingSummaryEdges( vertex: Vertex, - subscriptionData: SubscriptionData, + savedSubscription: SavedSubscription, ) { val summaries = summaryEdgesByStart[vertex].orEmpty() for (summaryEdge in summaries) { val notification = NotificationOnStart( - subscriptionData.subscriber, + savedSubscription.subscriber, runnerId, summaryEdge, - subscriptionData.edge + savedSubscription.edge ) parent.send(notification) } @@ -163,15 +163,15 @@ class RunnerStorage( private suspend fun sendEndNotificationsOnExistingSummaryEdges( vertex: Vertex, - subscriptionData: SubscriptionData, + savedSubscription: SavedSubscription, ) { val summaries = summaryEdgesByEnd[vertex].orEmpty() for (summaryEdge in summaries) { val notification = NotificationOnEnd( - subscriptionData.subscriber, + savedSubscription.subscriber, runnerId, summaryEdge, - subscriptionData.edge + savedSubscription.edge ) parent.send(notification) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt index 35ab46ad6..4a92dfb74 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt @@ -24,11 +24,11 @@ import org.jacodb.analysis.taint.NewVulnerability import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.analysis.taint.TaintEdge import org.jacodb.analysis.taint.TaintEvent -import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.analysis.taint.Tainted import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.ifds.taint.TaintVulnerability import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.taint.configuration.TaintMark import org.jacodb.taint.configuration.TaintMethodSink @@ -62,7 +62,7 @@ class NpeAnalyzer( if (fact.variable.isDereferencedAt(edge.to.statement)) { val message = "NPE" // TODO val vulnerability = TaintVulnerability(message, sink = edge.to) - logger.info { "Found sink=${vulnerability.sink} in ${vulnerability.method}" } + logger.info { "Found sink=${vulnerability.sink} in ${vulnerability.sink.statement.location.method}" } add(NewVulnerability(vulnerability)) } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt index 5004907ee..99937b6bf 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt @@ -23,6 +23,7 @@ import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.taint.TaintVulnerability import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.taint.configuration.TaintMethodSink @@ -72,7 +73,7 @@ class TaintAnalyzer( if (item.condition.accept(conditionEvaluator)) { val message = item.ruleNote val vulnerability = TaintVulnerability(message, sink = edge.to, rule = item) - logger.info { "Found sink=${vulnerability.sink} in ${vulnerability.method}" } + logger.info { "Found sink=${vulnerability.sink} in ${vulnerability.sink.statement.location.method}" } add(NewVulnerability(vulnerability)) } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt index 256070f9e..0ac52ecea 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt @@ -16,6 +16,8 @@ package org.jacodb.analysis.taint +import org.jacodb.ifds.taint.TaintVulnerability + sealed interface TaintEvent data class NewSummaryEdge( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt deleted file mode 100644 index abc24efe5..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintSummaries.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.taint - -import org.jacodb.analysis.ifds.Vulnerability -import org.jacodb.taint.configuration.TaintMethodSink - -data class TaintVulnerability( - override val message: String, - override val sink: TaintVertex, - val rule: TaintMethodSink? = null, -) : Vulnerability diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt deleted file mode 100644 index c5cf7c1f5..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableSummaries.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.unused - -import org.jacodb.analysis.ifds.Vulnerability -import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Vertex - -data class UnusedVariableVulnerability( - override val message: String, - override val sink: Vertex, -) : Vulnerability diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt index 8ceaa05c2..1e98ca498 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -62,7 +62,14 @@ fun npeIfdsContext( } is NewVulnerability -> { - val result = NewResult(runnerId, NpeVulnerability(event.vulnerability)) + val result = NewResult( + runnerId, + NpeVulnerability( + event.vulnerability.message, + event.vulnerability.sink, + event.vulnerability.rule + ) + ) add(result) } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt index de4c78f43..31dd1782e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt @@ -17,14 +17,17 @@ package org.jacodb.ifds.npe import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintVulnerability +import org.jacodb.analysis.taint.TaintVertex import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.IfdsResult +import org.jacodb.taint.configuration.TaintMethodSink data class NpeVulnerability( - val vulnerability: TaintVulnerability, + val message: String, + val sink: TaintVertex, + val rule: TaintMethodSink? = null, ) : IfdsResult { override val vertex: Vertex - get() = vulnerability.sink + get() = sink } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt index 56110d585..2b33e4274 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -30,8 +30,8 @@ import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.mergeIfdsResults +import org.jacodb.ifds.taint.TaintVulnerability import org.jacodb.impl.features.usagesExt -import org.jacodb.analysis.taint.TaintVulnerability as JcTaintVulnerability suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath @@ -46,10 +46,10 @@ suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { } } -suspend fun ActorSystem.collectNpeResults(): List = +suspend fun ActorSystem.collectNpeResults(): Collection = collectNpeComputationData() .results - .mapTo(mutableListOf()) { it.vulnerability } + suspend fun ActorSystem.collectNpeComputationData(): IfdsComputationData { val results = ask { CollectAll(SingletonRunnerId, it) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt index b79b527f7..21ecef503 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt @@ -39,7 +39,7 @@ data class VulnerabilityDescription( fun UnusedVulnerability.toSarif(): VulnerabilityInstance { return VulnerabilityInstance( EagerTraceGraph(vertex, mutableSetOf(vertex), mutableMapOf()), - VulnerabilityDescription(ruleId = null, message = vulnerability.message) + VulnerabilityDescription(ruleId = null, message = message) ) } @@ -50,7 +50,7 @@ fun TaintVulnerability.toSarif( graph, VulnerabilityDescription( ruleId = null, - message = this.vulnerability.rule?.ruleNote + message = this.rule?.ruleNote ) ) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt index 0c216d448..4d508f42e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -84,7 +84,7 @@ fun taintIfdsContext( } is NewVulnerability -> { - val result = IfdsNewResult(runnerId, TaintVulnerability(event.vulnerability)) + val result = IfdsNewResult(runnerId, event.vulnerability) add(result) } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt index 625fad22f..9fc186f28 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt @@ -17,14 +17,16 @@ package org.jacodb.ifds.taint import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.analysis.taint.TaintVertex import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.IfdsResult -import org.jacodb.analysis.taint.TaintVulnerability as JcTaintVulnerability +import org.jacodb.taint.configuration.TaintMethodSink data class TaintVulnerability( - val vulnerability: JcTaintVulnerability, + val message: String, + val sink: TaintVertex, + val rule: TaintMethodSink? = null, ) : IfdsResult { - override val vertex: Vertex - get() = vulnerability.sink + override val vertex: Vertex = sink } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index a525e1472..e4e93ef9f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -31,7 +31,6 @@ import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.mergeIfdsResults import org.jacodb.impl.features.usagesExt -import org.jacodb.analysis.taint.TaintVulnerability as JcTaintVulnerability suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath @@ -47,10 +46,9 @@ suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { } } -suspend fun ActorSystem.collectTaintResults(): List = +suspend fun ActorSystem.collectTaintResults(): Collection = collectTaintComputationData() .results - .mapTo(mutableListOf()) { it.vulnerability } suspend fun ActorSystem.collectTaintComputationData(): IfdsComputationData { val results = ask { CollectAll(ForwardRunnerId, it) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt index 2dad2a9ee..403ebf3c5 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt @@ -17,14 +17,14 @@ package org.jacodb.ifds.unused import org.jacodb.analysis.unused.UnusedVariableDomainFact -import org.jacodb.analysis.unused.UnusedVariableVulnerability import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.IfdsResult data class UnusedVulnerability( - val vulnerability: UnusedVariableVulnerability, + val message: String, + val sink: Vertex, ) : IfdsResult { override val vertex: Vertex - get() = vulnerability.sink + get() = sink } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt index 3daa4ce82..3f320b83d 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -21,7 +21,6 @@ import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.unused.UnusedVariable import org.jacodb.analysis.unused.UnusedVariableAnalyzer import org.jacodb.analysis.unused.UnusedVariableDomainFact -import org.jacodb.analysis.unused.UnusedVariableVulnerability import org.jacodb.analysis.unused.UnusedVariableZeroFact import org.jacodb.analysis.unused.isUsedAt import org.jacodb.api.JcMethod @@ -50,7 +49,7 @@ suspend fun ActorSystem.startUnusedAnalysis(method: JcMethod) { } } -suspend fun ActorSystem.collectUnusedResult(): List { +suspend fun ActorSystem.collectUnusedResult(): Collection { val data = collectUnusedComputationData() val allFacts = data.facts @@ -68,7 +67,7 @@ suspend fun ActorSystem.collectUnusedResult(): List List>) { + protected fun testSingleJulietClass(className: String, findSinks: (JcMethod) -> Collection>) { logger.info { className } val clazz = cp.findClass(className) diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt index 2918e40bf..1bd7d7983 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt @@ -20,11 +20,11 @@ import kotlinx.coroutines.runBlocking import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.api.JcMethod import org.jacodb.api.ext.constructors import org.jacodb.api.ext.findClass import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.npe.NpeVulnerability import org.jacodb.ifds.npe.collectNpeResults import org.jacodb.ifds.npe.npeIfdsContext import org.jacodb.ifds.npe.startNpeAnalysis @@ -198,7 +198,7 @@ class IfdsNpeTest : BaseAnalysisTest() { testOneMethod("nullAssignmentToCopy", emptyList()) } - private fun findSinks(method: JcMethod): List = runBlocking { + private fun findSinks(method: JcMethod): Collection = runBlocking { val ifdsContext = npeIfdsContext(cp, graph, defaultBannedPackagePrefixes) val system = system("ifds") { ProjectManager(ifdsContext) } diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index cc189a067..b226695f1 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -21,7 +21,6 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.taint.TaintVulnerability import org.jacodb.analysis.taint.TaintZeroFact import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass @@ -30,6 +29,7 @@ import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.result.buildTraceGraph import org.jacodb.ifds.sarif.sarifReportFromVulnerabilities import org.jacodb.ifds.sarif.toSarif +import org.jacodb.ifds.taint.TaintVulnerability import org.jacodb.ifds.taint.collectTaintComputationData import org.jacodb.ifds.taint.collectTaintResults import org.jacodb.ifds.taint.startTaintAnalysis @@ -82,7 +82,7 @@ class IfdsSqlTest : BaseAnalysisTest() { assertTrue(trace.isNotEmpty()) } - private fun findSinks(method: JcMethod): List = runBlocking { + private fun findSinks(method: JcMethod): Collection = runBlocking { val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) val system = system("ifds") { ProjectManager(ifdsContext) } diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt index 6ed961014..b8f8d1166 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt @@ -19,11 +19,11 @@ package org.jacodb.analysis.impl import kotlinx.coroutines.runBlocking import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.unused.UnusedVariableVulnerability import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.unused.UnusedVulnerability import org.jacodb.ifds.unused.collectUnusedResult import org.jacodb.ifds.unused.startUnusedAnalysis import org.jacodb.ifds.unused.unusedIfdsContext @@ -61,7 +61,7 @@ class IfdsUnusedTest : BaseAnalysisTest() { ) } - private fun findSinks(method: JcMethod): List = runBlocking { + private fun findSinks(method: JcMethod): Collection = runBlocking { val ifdsContext = unusedIfdsContext(cp, graph, defaultBannedPackagePrefixes) val system = system("ifds") { ProjectManager(ifdsContext) } From b2862b1e109563a6e6658c6225b2dcecf8984e19 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 12:37:38 +0300 Subject: [PATCH 34/64] [ifds] wip: change flow functions interface --- .../org/jacodb/analysis/ifds/FlowFunctions.kt | 25 ++--- .../org/jacodb/analysis/ifds/Summary.kt | 38 ------- .../jacodb/analysis/npe/NpeFlowFunctions.kt | 71 ++++++------ .../analysis/taint/TaintFlowFunctions.kt | 103 ++++++++++-------- .../unused/UnusedVariableFlowFunctions.kt | 43 ++++---- .../kotlin/org/jacodb/ifds/FunctionWrapper.kt | 12 +- .../jacodb/analysis/impl/BaseAnalysisTest.kt | 1 - .../analysis/impl/TaintFlowFunctionsTest.kt | 44 ++++---- 8 files changed, 155 insertions(+), 182 deletions(-) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt index 7a93eaee7..ceac4bc3b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt @@ -19,12 +19,7 @@ package org.jacodb.analysis.ifds import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst -fun interface FlowFunction { - fun compute(fact: Fact): Collection -} - interface FlowFunctions { - /** * Method for obtaining initial domain facts at the method entrypoint. * Commonly, it is only `listOf(Zero)`. @@ -42,10 +37,11 @@ interface FlowFunctions { * [ DO() ] * ``` */ - fun obtainSequentFlowFunction( + fun sequent( current: JcInst, next: JcInst, - ): FlowFunction + fact: Fact, + ): Collection /** * Call-to-return-site flow function. @@ -58,10 +54,11 @@ interface FlowFunctions { * [ RETURN FROM p ] :: returnSite * ``` */ - fun obtainCallToReturnSiteFlowFunction( + fun callToReturn( callStatement: JcInst, returnSite: JcInst, - ): FlowFunction + fact: Fact + ): Collection /** * Call-to-start flow function. @@ -79,10 +76,11 @@ interface FlowFunctions { * [ RETURN FROM p ] * ``` */ - fun obtainCallToStartFlowFunction( + fun callToStart( callStatement: JcInst, calleeStart: JcInst, - ): FlowFunction + fact: Fact, + ): Collection /** * Exit-to-return-site flow function. @@ -100,9 +98,10 @@ interface FlowFunctions { * [ RETURN FROM p ] :: returnSite * ``` */ - fun obtainExitToReturnSiteFlowFunction( + fun exitToReturnSite( callStatement: JcInst, returnSite: JcInst, exitStatement: JcInst, - ): FlowFunction + fact: Fact, + ): Collection } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt deleted file mode 100644 index e792ca3a2..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Summary.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.JcMethod -import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Vertex - -/** - * A common interface for anything that should be remembered - * and used after the analysis of some unit is completed. - */ -interface Summary { - val method: JcMethod -} - -interface Vulnerability : Summary { - val message: String - val sink: Vertex - - override val method: JcMethod - get() = sink.statement.location.method -} - diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt index dbdbfec98..4fff36a4c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt @@ -25,7 +25,6 @@ import org.jacodb.analysis.config.FactAwareConditionEvaluator import org.jacodb.analysis.config.TaintActionEvaluator import org.jacodb.analysis.ifds.AccessPath import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FlowFunction import org.jacodb.analysis.ifds.FlowFunctions import org.jacodb.analysis.ifds.onSome import org.jacodb.analysis.ifds.toPath @@ -212,13 +211,14 @@ class ForwardNpeFlowFunctions( } } - override fun obtainSequentFlowFunction( + override fun sequent( current: JcInst, next: JcInst, - ) = FlowFunction { fact -> + fact: TaintDomainFact + ): Collection { if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { if (fact.variable.isDereferencedAt(current)) { - return@FlowFunction emptySet() + return emptySet() } } @@ -233,29 +233,29 @@ class ForwardNpeFlowFunctions( // This is a hack: instructions like `return null` in branch of next will be considered only if // the fact holds (otherwise we could not get there) // Note the absence of 'Zero' here! - return@FlowFunction listOf(Tainted(pathComparedWithNull, TaintMark.NULLNESS)) + return listOf(Tainted(pathComparedWithNull, TaintMark.NULLNESS)) } } } else if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { val expr = current.condition if (pathComparedWithNull != fact.variable) { - return@FlowFunction listOf(fact) + return listOf(fact) } if ((expr is JcEqExpr && nextIsTrueBranch) || (expr is JcNeqExpr && !nextIsTrueBranch)) { // comparedPath is null in this branch - return@FlowFunction listOf(TaintZeroFact) + return listOf(TaintZeroFact) } else { - return@FlowFunction emptyList() + return emptyList() } } } if (fact is TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) + generates(current) + return listOf(TaintZeroFact) + generates(current) } check(fact is Tainted) - if (current is JcAssignInst) { + return if (current is JcAssignInst) { transmitTaintAssign(fact, from = current.rhv, to = current.lhv) } else { transmitTaintNormal(fact, current) @@ -318,13 +318,14 @@ class ForwardNpeFlowFunctions( to: JcValue, ): Collection = transmitTaint(fact, at, from, to) - override fun obtainCallToReturnSiteFlowFunction( + override fun callToReturn( callStatement: JcInst, - returnSite: JcInst, // FIXME: unused? - ) = FlowFunction { fact -> + returnSite: JcInst, + fact: TaintDomainFact + ): Collection { if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { if (fact.variable.isDereferencedAt(callStatement)) { - return@FlowFunction emptySet() + return emptySet() } } @@ -340,19 +341,19 @@ class ForwardNpeFlowFunctions( ) { for (arg in callExpr.args) { if (arg.toPath() == fact.variable) { - return@FlowFunction setOf( + return setOf( fact, fact.copy(variable = callStatement.lhv.toPath()) ) } } - return@FlowFunction setOf(fact) + return setOf(fact) } val config = taintConfigurationFeature?.getConfigForMethod(callee) if (fact == TaintZeroFact) { - return@FlowFunction buildSet { + return buildSet { add(TaintZeroFact) if (callStatement is JcAssignInst) { @@ -441,7 +442,7 @@ class ForwardNpeFlowFunctions( if (facts.size > 0) { logger.trace { "Got ${facts.size} facts from config for $callee: $facts" } } - return@FlowFunction facts + return facts } else { // Fall back to the default behavior, as if there were no config at all. } @@ -450,7 +451,7 @@ class ForwardNpeFlowFunctions( // FIXME: adhoc for constructors: if (callee.isConstructor) { - return@FlowFunction listOf(fact) + return listOf(fact) } // TODO: CONSIDER REFACTORING THIS @@ -465,20 +466,20 @@ class ForwardNpeFlowFunctions( if (callee in graph.callees(callStatement)) { if (fact.variable.isStatic) { - return@FlowFunction emptyList() + return emptyList() } for (actual in callExpr.args) { // Possibly tainted actual parameter: if (fact.variable.startsWith(actual.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge + return emptyList() // Will be handled by summary edge } } if (callExpr is JcInstanceCallExpr) { // Possibly tainted instance: if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge + return emptyList() // Will be handled by summary edge } } @@ -487,29 +488,30 @@ class ForwardNpeFlowFunctions( if (callStatement is JcAssignInst) { // Possibly tainted lhv: if (fact.variable.startsWith(callStatement.lhv.toPathOrNull())) { - return@FlowFunction emptyList() // Overridden by rhv + return emptyList() // Overridden by rhv } } // The "most default" behaviour is encapsulated here: - transmitTaintNormal(fact, callStatement) + return transmitTaintNormal(fact, callStatement) } - override fun obtainCallToStartFlowFunction( + override fun callToStart( callStatement: JcInst, calleeStart: JcInst, - ) = FlowFunction { fact -> + fact: TaintDomainFact + ): Collection { val callee = calleeStart.location.method if (fact == TaintZeroFact) { - return@FlowFunction obtainPossibleStartFactsBasic(callee) + return obtainPossibleStartFactsBasic(callee) } check(fact is Tainted) val callExpr = callStatement.callExpr ?: error("Call statement should have non-null callExpr") - buildSet { + return buildSet { // Transmit facts on arguments (from 'actual' to 'formal'): val actualParams = callExpr.args val formalParams = cp.getArgumentsOf(callee) @@ -543,15 +545,16 @@ class ForwardNpeFlowFunctions( } } - override fun obtainExitToReturnSiteFlowFunction( + override fun exitToReturnSite( callStatement: JcInst, - returnSite: JcInst, // unused + returnSite: JcInst, exitStatement: JcInst, - ) = FlowFunction { fact -> + fact: TaintDomainFact + ): Collection { // TODO: do we even need to return non-empty list for zero fact here? if (fact == TaintZeroFact) { - // return@FlowFunctions listOf(Zero) - return@FlowFunction buildSet { + // returns listOf(Zero) + return buildSet { add(TaintZeroFact) if (exitStatement is JcReturnInst && callStatement is JcAssignInst) { // Note: returnValue can be null here in some weird cases, e.g. in lambda. @@ -570,7 +573,7 @@ class ForwardNpeFlowFunctions( ?: error("Call statement should have non-null callExpr") val callee = exitStatement.location.method - buildSet { + return buildSet { // Transmit facts on arguments (from 'formal' back to 'actual'), if they are passed by-ref: if (fact.variable.isOnHeap) { val actualParams = callExpr.args diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt index 20bc9b455..3d95fb23f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt @@ -24,7 +24,6 @@ import org.jacodb.analysis.config.EntryPointPositionToJcValueResolver import org.jacodb.analysis.config.FactAwareConditionEvaluator import org.jacodb.analysis.config.TaintActionEvaluator import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FlowFunction import org.jacodb.analysis.ifds.FlowFunctions import org.jacodb.analysis.ifds.onSome import org.jacodb.analysis.ifds.toPath @@ -144,16 +143,17 @@ class ForwardTaintFlowFunctions( return listOf(fact) } - override fun obtainSequentFlowFunction( + override fun sequent( current: JcInst, next: JcInst, - ) = FlowFunction { fact -> + fact: TaintDomainFact + ): Collection { if (fact is TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) + return listOf(TaintZeroFact) } check(fact is Tainted) - if (current is JcAssignInst) { + return if (current is JcAssignInst) { transmitTaintAssign(fact, from = current.rhv, to = current.lhv) } else { transmitTaintNormal(fact, current) @@ -204,10 +204,11 @@ class ForwardTaintFlowFunctions( to: JcValue, ): Collection = transmitTaint(fact, from, to) - override fun obtainCallToReturnSiteFlowFunction( + override fun callToReturn( callStatement: JcInst, - returnSite: JcInst, // FIXME: unused? - ) = FlowFunction { fact -> + returnSite: JcInst, + fact: TaintDomainFact + ): Collection { val callExpr = callStatement.callExpr ?: error("Call statement should have non-null callExpr") val callee = callExpr.method.method @@ -220,19 +221,19 @@ class ForwardTaintFlowFunctions( ) { for (arg in callExpr.args) { if (arg.toPath() == fact.variable) { - return@FlowFunction setOf( + return setOf( fact, fact.copy(variable = callStatement.lhv.toPath()) ) } } - return@FlowFunction setOf(fact) + return setOf(fact) } val config = taintConfigurationFeature?.getConfigForMethod(callee) if (fact == TaintZeroFact) { - return@FlowFunction buildSet { + return buildSet { add(TaintZeroFact) if (config != null) { @@ -302,7 +303,7 @@ class ForwardTaintFlowFunctions( if (facts.size > 0) { logger.trace { "Got ${facts.size} facts from config for $callee: $facts" } } - return@FlowFunction facts + return facts } else { // Fall back to the default behavior, as if there were no config at all. } @@ -310,7 +311,7 @@ class ForwardTaintFlowFunctions( // FIXME: adhoc for constructors: if (callee.isConstructor) { - return@FlowFunction listOf(fact) + return listOf(fact) } // TODO: CONSIDER REFACTORING THIS @@ -325,20 +326,20 @@ class ForwardTaintFlowFunctions( if (callee in graph.callees(callStatement)) { if (fact.variable.isStatic) { - return@FlowFunction emptyList() + return emptyList() } for (actual in callExpr.args) { // Possibly tainted actual parameter: if (fact.variable.startsWith(actual.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge + return emptyList() // Will be handled by summary edge } } if (callExpr is JcInstanceCallExpr) { // Possibly tainted instance: if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge + return emptyList() // Will be handled by summary edge } } @@ -347,29 +348,30 @@ class ForwardTaintFlowFunctions( if (callStatement is JcAssignInst) { // Possibly tainted lhv: if (fact.variable.startsWith(callStatement.lhv.toPathOrNull())) { - return@FlowFunction emptyList() // Overridden by rhv + return emptyList() // Overridden by rhv } } // The "most default" behaviour is encapsulated here: - transmitTaintNormal(fact, callStatement) + return transmitTaintNormal(fact, callStatement) } - override fun obtainCallToStartFlowFunction( + override fun callToStart( callStatement: JcInst, calleeStart: JcInst, - ) = FlowFunction { fact -> + fact: TaintDomainFact + ): Collection { val callee = calleeStart.location.method if (fact == TaintZeroFact) { - return@FlowFunction obtainPossibleStartFacts(callee) + return obtainPossibleStartFacts(callee) } check(fact is Tainted) val callExpr = callStatement.callExpr ?: error("Call statement should have non-null callExpr") - buildSet { + return buildSet { // Transmit facts on arguments (from 'actual' to 'formal'): val actualParams = callExpr.args val formalParams = cp.getArgumentsOf(callee) @@ -389,13 +391,14 @@ class ForwardTaintFlowFunctions( } } - override fun obtainExitToReturnSiteFlowFunction( + override fun exitToReturnSite( callStatement: JcInst, - returnSite: JcInst, // unused + returnSite: JcInst, exitStatement: JcInst, - ) = FlowFunction { fact -> + fact: TaintDomainFact + ): Collection { if (fact == TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) + return listOf(TaintZeroFact) } check(fact is Tainted) @@ -403,7 +406,7 @@ class ForwardTaintFlowFunctions( ?: error("Call statement should have non-null callExpr") val callee = exitStatement.location.method - buildSet { + return buildSet { // Transmit facts on arguments (from 'formal' back to 'actual'), if they are passed by-ref: if (fact.variable.isOnHeap) { val actualParams = callExpr.args @@ -480,16 +483,17 @@ class BackwardTaintFlowFunctions( return listOf(fact) } - override fun obtainSequentFlowFunction( + override fun sequent( current: JcInst, next: JcInst, - ) = FlowFunction { fact -> + fact: TaintDomainFact + ): Collection { if (fact is TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) + return listOf(TaintZeroFact) } check(fact is Tainted) - if (current is JcAssignInst) { + return if (current is JcAssignInst) { transmitTaintBackwardAssign(fact, from = current.lhv, to = current.rhv) } else { transmitTaintBackwardNormal(fact, current) @@ -540,14 +544,15 @@ class BackwardTaintFlowFunctions( to: JcValue, ): Collection = transmitTaint(fact, from, to) - override fun obtainCallToReturnSiteFlowFunction( + override fun callToReturn( callStatement: JcInst, - returnSite: JcInst, // FIXME: unused? - ) = FlowFunction { fact -> + returnSite: JcInst, + fact: TaintDomainFact + ): Collection { // TODO: pass-through on invokedynamic-based String concatenation if (fact == TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) + return listOf(TaintZeroFact) } check(fact is Tainted) @@ -558,20 +563,20 @@ class BackwardTaintFlowFunctions( if (callee in graph.callees(callStatement)) { if (fact.variable.isStatic) { - return@FlowFunction emptyList() + return emptyList() } for (actual in callExpr.args) { // Possibly tainted actual parameter: if (fact.variable.startsWith(actual.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge + return emptyList() // Will be handled by summary edge } } if (callExpr is JcInstanceCallExpr) { // Possibly tainted instance: if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return@FlowFunction emptyList() // Will be handled by summary edge + return emptyList() // Will be handled by summary edge } } @@ -580,29 +585,30 @@ class BackwardTaintFlowFunctions( if (callStatement is JcAssignInst) { // Possibly tainted rhv: if (fact.variable.startsWith(callStatement.rhv.toPathOrNull())) { - return@FlowFunction emptyList() // Overridden by lhv + return emptyList() // Overridden by lhv } } // The "most default" behaviour is encapsulated here: - transmitTaintBackwardNormal(fact, callStatement) + return transmitTaintBackwardNormal(fact, callStatement) } - override fun obtainCallToStartFlowFunction( + override fun callToStart( callStatement: JcInst, calleeStart: JcInst, - ) = FlowFunction { fact -> + fact: TaintDomainFact + ): Collection { val callee = calleeStart.location.method if (fact == TaintZeroFact) { - return@FlowFunction obtainPossibleStartFacts(callee) + return obtainPossibleStartFacts(callee) } check(fact is Tainted) val callExpr = callStatement.callExpr ?: error("Call statement should have non-null callExpr") - buildSet { + return buildSet { // Transmit facts on arguments (from 'actual' to 'formal'): val actualParams = callExpr.args val formalParams = project.getArgumentsOf(callee) @@ -636,13 +642,14 @@ class BackwardTaintFlowFunctions( } } - override fun obtainExitToReturnSiteFlowFunction( + override fun exitToReturnSite( callStatement: JcInst, returnSite: JcInst, exitStatement: JcInst, - ) = FlowFunction { fact -> + fact: TaintDomainFact + ): Collection { if (fact == TaintZeroFact) { - return@FlowFunction listOf(TaintZeroFact) + return listOf(TaintZeroFact) } check(fact is Tainted) @@ -650,7 +657,7 @@ class BackwardTaintFlowFunctions( ?: error("Call statement should have non-null callExpr") val callee = exitStatement.location.method - buildSet { + return buildSet { // Transmit facts on arguments (from 'formal' back to 'actual'), if they are passed by-ref: if (fact.variable.isOnHeap) { val actualParams = callExpr.args diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt index bd9e3289a..287bd7df8 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt @@ -16,7 +16,6 @@ package org.jacodb.analysis.unused -import org.jacodb.analysis.ifds.FlowFunction import org.jacodb.analysis.ifds.FlowFunctions import org.jacodb.analysis.ifds.toPath import org.jacodb.analysis.ifds.toPathOrNull @@ -42,20 +41,21 @@ class UnusedVariableFlowFunctions( return setOf(UnusedVariableZeroFact) } - override fun obtainSequentFlowFunction( + override fun sequent( current: JcInst, next: JcInst, - ) = FlowFunction { fact -> + fact: UnusedVariableDomainFact + ): Collection { if (current !is JcAssignInst) { - return@FlowFunction setOf(fact) + return setOf(fact) } if (fact == UnusedVariableZeroFact) { val toPath = current.lhv.toPath() if (!toPath.isOnHeap) { - return@FlowFunction setOf(UnusedVariableZeroFact, UnusedVariable(toPath, current)) + return setOf(UnusedVariableZeroFact, UnusedVariable(toPath, current)) } else { - return@FlowFunction setOf(UnusedVariableZeroFact) + return setOf(UnusedVariableZeroFact) } } check(fact is UnusedVariable) @@ -63,36 +63,38 @@ class UnusedVariableFlowFunctions( val toPath = current.lhv.toPath() val default = if (toPath == fact.variable) emptySet() else setOf(fact) val fromPath = current.rhv.toPathOrNull() - ?: return@FlowFunction default + ?: return default if (fromPath.isOnHeap || toPath.isOnHeap) { - return@FlowFunction default + return default } if (fromPath == fact.variable) { - return@FlowFunction default + fact.copy(variable = toPath) + return default + fact.copy(variable = toPath) } - default + return default } - override fun obtainCallToReturnSiteFlowFunction( + override fun callToReturn( callStatement: JcInst, returnSite: JcInst, - ) = obtainSequentFlowFunction(callStatement, returnSite) + fact: UnusedVariableDomainFact + ): Collection = sequent(callStatement, returnSite, fact) - override fun obtainCallToStartFlowFunction( + override fun callToStart( callStatement: JcInst, calleeStart: JcInst, - ) = FlowFunction { fact -> + fact: UnusedVariableDomainFact + ): Collection { val callExpr = callStatement.callExpr ?: error("Call statement should have non-null callExpr") if (fact == UnusedVariableZeroFact) { if (callExpr !is JcStaticCallExpr && callExpr !is JcSpecialCallExpr) { - return@FlowFunction setOf(UnusedVariableZeroFact) + return setOf(UnusedVariableZeroFact) } - return@FlowFunction buildSet { + return buildSet { add(UnusedVariableZeroFact) val callee = calleeStart.location.method val formalParams = cp.getArgumentsOf(callee) @@ -103,15 +105,16 @@ class UnusedVariableFlowFunctions( } check(fact is UnusedVariable) - emptySet() + return emptySet() } - override fun obtainExitToReturnSiteFlowFunction( + override fun exitToReturnSite( callStatement: JcInst, returnSite: JcInst, exitStatement: JcInst, - ) = FlowFunction { fact -> - if (fact == UnusedVariableZeroFact) { + fact: UnusedVariableDomainFact + ): Collection { + return if (fact == UnusedVariableZeroFact) { setOf(UnusedVariableZeroFact) } else { emptySet() diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt index ec80eaaef..7852abd72 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt @@ -38,8 +38,7 @@ class JcFlowFunctionsAdapter( override fun FlowScope.sequent(next: JcInst) = jcFlowFunctions - .obtainSequentFlowFunction(edge.to.statement, next) - .compute(edge.to.fact) + .sequent(edge.to.statement, next, edge.to.fact) .forEach { newFact -> val newEdge = Edge(edge.from, Vertex(next, newFact)) processNewEdge(runnerId, newEdge, Reason.Sequent(edge)) @@ -47,8 +46,7 @@ class JcFlowFunctionsAdapter( override fun FlowScope.callToReturn(returnSite: JcInst) = jcFlowFunctions - .obtainCallToReturnSiteFlowFunction(edge.to.statement, returnSite) - .compute(edge.to.fact) + .callToReturn(edge.to.statement, returnSite, edge.to.fact) .forEach { newFact -> val newEdge = Edge(edge.from, Vertex(returnSite, newFact)) processNewEdge(runnerId, newEdge, Reason.CallToReturn(edge)) @@ -56,8 +54,7 @@ class JcFlowFunctionsAdapter( override fun FlowScope.callToStart(calleeStart: JcInst) = jcFlowFunctions - .obtainCallToStartFlowFunction(edge.to.statement, calleeStart) - .compute(edge.to.fact) + .callToStart(edge.to.statement, calleeStart, edge.to.fact) .forEach { newFact -> val vertex = Vertex(calleeStart, newFact) @@ -72,8 +69,7 @@ class JcFlowFunctionsAdapter( callerEdge: Edge, returnSite: JcInst, ) = jcFlowFunctions - .obtainExitToReturnSiteFlowFunction(callerEdge.to.statement, returnSite, edge.to.statement) - .compute(edge.to.fact) + .exitToReturnSite(callerEdge.to.statement, returnSite, edge.to.statement, edge.to.fact) .forEach { newFact -> val newEdge = Edge(callerEdge.from, Vertex(returnSite, newFact)) processNewEdge(runnerId, newEdge, Reason.ExitToReturnSite(callerEdge, edge)) diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt index 9659df027..2cf9be2ca 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt @@ -19,7 +19,6 @@ package org.jacodb.analysis.impl import juliet.support.AbstractTestCase import kotlinx.coroutines.runBlocking import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.ifds.Vulnerability import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt index e37c753b4..03e477e41 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt @@ -20,12 +20,12 @@ import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.runBlocking import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.util.getArgument import org.jacodb.analysis.ifds.toPath import org.jacodb.analysis.taint.ForwardTaintFlowFunctions import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.Tainted import org.jacodb.analysis.taint.TaintZeroFact +import org.jacodb.analysis.taint.Tainted +import org.jacodb.analysis.util.getArgument import org.jacodb.api.JcClassType import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod @@ -112,10 +112,9 @@ class TaintFlowFunctionsTest : BaseTest() { val y: JcLocal = JcLocalVar(2, "y", stringType) val inst = JcAssignInst(location = mockk(), lhv = x, rhv = y) val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) - val f = flowSpace.obtainSequentFlowFunction(inst, next = mockk()) val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) - val facts = f.compute(yTaint).toList() + val facts = flowSpace.sequent(inst, next = mockk(), yTaint).toList() Assertions.assertEquals(listOf(yTaint, xTaint), facts) } @@ -129,9 +128,8 @@ class TaintFlowFunctionsTest : BaseTest() { } }) val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) - val f = flowSpace.obtainCallToReturnSiteFlowFunction(callStatement, returnSite = mockk()) val xTaint = Tainted(x.toPath(), TaintMark("EXAMPLE")) - val facts = f.compute(TaintZeroFact).toList() + val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), TaintZeroFact).toList() Assertions.assertEquals(listOf(TaintZeroFact, xTaint), facts) } @@ -146,9 +144,8 @@ class TaintFlowFunctionsTest : BaseTest() { every { args } returns listOf(x) }) val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) - val f = flowSpace.obtainCallToReturnSiteFlowFunction(callStatement, returnSite = mockk()) val xTaint = Tainted(x.toPath(), TaintMark("REMOVE")) - val facts = f.compute(xTaint).toList() + val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() Assertions.assertTrue(facts.isEmpty()) } @@ -164,14 +161,13 @@ class TaintFlowFunctionsTest : BaseTest() { every { args } returns listOf(x) }) val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) - val f = flowSpace.obtainCallToReturnSiteFlowFunction(callStatement, returnSite = mockk()) val xTaint = Tainted(x.toPath(), TaintMark("COPY")) val yTaint = Tainted(y.toPath(), TaintMark("COPY")) - val facts = f.compute(xTaint).toList() + val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() Assertions.assertEquals(listOf(xTaint, yTaint), facts) // copy from x to y val other: JcLocal = JcLocalVar(10, "other", stringType) val otherTaint = Tainted(other.toPath(), TaintMark("OTHER")) - val facts2 = f.compute(otherTaint).toList() + val facts2 = flowSpace.callToReturn(callStatement, returnSite = mockk(), otherTaint).toList() Assertions.assertEquals(listOf(otherTaint), facts2) // pass-through } @@ -186,19 +182,28 @@ class TaintFlowFunctionsTest : BaseTest() { every { args } returns listOf(x) }) val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) - val f = flowSpace.obtainCallToStartFlowFunction(callStatement, calleeStart = mockk { - every { location } returns mockk { - every { method } returns testMethod - } - }) + val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val arg0: JcArgument = cp.getArgument(testMethod.parameters[0])!! val arg0Taint = Tainted(arg0.toPath(), TaintMark("TAINT")) - val facts = f.compute(xTaint).toList() + val calleeStart = mockk { + every { location } returns mockk { + every { method } returns testMethod + } + } + val facts = flowSpace.callToStart( + callStatement, + calleeStart = calleeStart, + xTaint + ).toList() Assertions.assertEquals(listOf(arg0Taint), facts) val other: JcLocal = JcLocalVar(10, "other", stringType) val otherTaint = Tainted(other.toPath(), TaintMark("TAINT")) - val facts2 = f.compute(otherTaint).toList() + val facts2 = flowSpace.callToStart( + callStatement, + calleeStart = calleeStart, + otherTaint + ).toList() Assertions.assertTrue(facts2.isEmpty()) } @@ -216,10 +221,9 @@ class TaintFlowFunctionsTest : BaseTest() { every { method } returns testMethod }, returnValue = y) val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) - val f = flowSpace.obtainExitToReturnSiteFlowFunction(callStatement, returnSite = mockk(), exitStatement) val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) - val facts = f.compute(yTaint).toList() + val facts = flowSpace.exitToReturnSite(callStatement, returnSite = mockk(), exitStatement, yTaint) Assertions.assertEquals(listOf(xTaint), facts) } } From 69dcfd0dfe8fb476056d1aa6098833d816990897 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 13:12:35 +0300 Subject: [PATCH 35/64] [ifds] wip: change flow functions interface, renamings --- .../kotlin/org/jacodb/ifds/ChunkResolver.kt | 4 +-- .../org/jacodb/ifds/actors/RunnerStorage.kt | 4 +-- .../jacodb/ifds/messages/AnalyzerMessages.kt | 8 +++--- .../jacodb/ifds/messages/StorageMessages.kt | 4 +-- .../org/jacodb/analysis/ifds/Analyzer.kt | 7 ++++++ .../org/jacodb/analysis/ifds/FlowFunctions.kt | 7 ------ .../org/jacodb/analysis/npe/NpeAnalyzers.kt | 16 +++++++++--- .../jacodb/analysis/npe/NpeFlowFunctions.kt | 10 ++------ .../jacodb/analysis/taint/TaintAnalyzers.kt | 25 ++++++++++++++++--- .../analysis/taint/TaintFlowFunctions.kt | 12 +++------ .../analysis/unused/UnusedVariableAnalyzer.kt | 5 +++- .../unused/UnusedVariableFlowFunctions.kt | 6 ----- .../kotlin/org/jacodb/ifds/DefaultAnalyzer.kt | 6 ++--- .../org/jacodb/ifds/npe/SystemExtensions.kt | 3 +-- .../org/jacodb/ifds/taint/SystemExtensions.kt | 2 +- .../jacodb/ifds/unused/SystemExtensions.kt | 2 +- .../analysis/impl/TaintFlowFunctionsTest.kt | 24 +++++++++--------- 17 files changed, 78 insertions(+), 67 deletions(-) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt index 0aa6a8852..6e902f405 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt @@ -56,12 +56,12 @@ class DefaultChunkResolver( is NotificationOnEnd<*, *> -> { message as NotificationOnEnd - chunkStrategy.chunkByStmt(message.edge.to.statement) + chunkStrategy.chunkByStmt(message.summaryEdge.to.statement) } is NotificationOnStart<*, *> -> { message as NotificationOnStart - chunkStrategy.chunkByStmt(message.edge.to.statement) + chunkStrategy.chunkByStmt(message.summaryEdge.to.statement) } is ResolvedCall<*, *, *> -> { diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt index efd7c3045..a7fa68c42 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt @@ -103,7 +103,7 @@ class RunnerStorage( @Suppress("UNCHECKED_CAST") message as SubscriptionOnStart - val savedSubscription = SavedSubscription(message.data, message.subscriber) + val savedSubscription = SavedSubscription(message.subscribingEdge, message.subscriber) sendStartNotificationsOnExistingSummaryEdges(message.startVertex, savedSubscription) @@ -116,7 +116,7 @@ class RunnerStorage( @Suppress("UNCHECKED_CAST") message as SubscriptionOnEnd - val savedSubscription = SavedSubscription(message.data, message.subscriber) + val savedSubscription = SavedSubscription(message.subscribingEdge, message.subscriber) sendEndNotificationsOnExistingSummaryEdges(message.endVertex, savedSubscription) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt index 5cc0414c4..04617add8 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt @@ -35,13 +35,13 @@ data class ResolvedCall( data class NotificationOnStart( override val runnerId: RunnerId, val author: RunnerId, - val edge: Edge, - val data: Edge, + val summaryEdge: Edge, + val subscribingEdge: Edge, ) : AnalyzerMessage data class NotificationOnEnd( override val runnerId: RunnerId, val author: RunnerId, - val edge: Edge, - val data: Edge, + val summaryEdge: Edge, + val subscribingEdge: Edge, ) : AnalyzerMessage diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt index 3619017f2..c314125bc 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt @@ -42,14 +42,14 @@ data class SubscriptionOnStart( override val runnerId: RunnerId, val startVertex: Vertex, val subscriber: RunnerId, - val data: Edge, + val subscribingEdge: Edge, ) : StorageMessage data class SubscriptionOnEnd( override val runnerId: RunnerId, val endVertex: Vertex, val subscriber: RunnerId, - val data: Edge, + val subscribingEdge: Edge, ) : StorageMessage data class NewResult( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt index a362f70ab..bbd198a78 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt @@ -16,12 +16,19 @@ package org.jacodb.analysis.ifds +import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge interface Analyzer { val flowFunctions: FlowFunctions + /** + * Method for obtaining initial domain facts at the method entrypoint. + * Commonly, it is only `listOf(Zero)`. + */ + fun obtainPossibleStartFacts(method: JcMethod): Collection + fun handleNewEdge( edge: Edge, ): List diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt index ceac4bc3b..6d2dddd3e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt @@ -16,16 +16,9 @@ package org.jacodb.analysis.ifds -import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst interface FlowFunctions { - /** - * Method for obtaining initial domain facts at the method entrypoint. - * Commonly, it is only `listOf(Zero)`. - */ - fun obtainPossibleStartFacts(method: JcMethod): Collection - /** * Sequent flow function. * diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt index 4a92dfb74..cf399152e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt @@ -25,6 +25,7 @@ import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.analysis.taint.TaintEdge import org.jacodb.analysis.taint.TaintEvent import org.jacodb.analysis.taint.Tainted +import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr @@ -35,16 +36,25 @@ import org.jacodb.taint.configuration.TaintMethodSink private val logger = mu.KotlinLogging.logger {} + class NpeAnalyzer( private val graph: JcApplicationGraph, ) : Analyzer { + val cp = graph.classpath + + private val taintConfigurationFeature: TaintConfigurationFeature? by lazy { + cp.features + ?.singleOrNull { it is TaintConfigurationFeature } + ?.let { it as TaintConfigurationFeature } + } + override val flowFunctions: ForwardNpeFlowFunctions by lazy { - ForwardNpeFlowFunctions(graph.classpath, graph) + ForwardNpeFlowFunctions(cp, graph, taintConfigurationFeature) } - private val taintConfigurationFeature: TaintConfigurationFeature? - get() = flowFunctions.taintConfigurationFeature + override fun obtainPossibleStartFacts(method: JcMethod): Collection = + flowFunctions.obtainPossibleStartFacts(method) private fun isExitPoint(statement: JcInst): Boolean { return statement in graph.exitPoints(statement.location.method) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt index 4fff36a4c..aa2b3c28e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt @@ -74,15 +74,9 @@ private val logger = mu.KotlinLogging.logger {} class ForwardNpeFlowFunctions( private val cp: JcClasspath, private val graph: JcApplicationGraph, + private val taintConfigurationFeature: TaintConfigurationFeature?, ) : FlowFunctions { - - internal val taintConfigurationFeature: TaintConfigurationFeature? by lazy { - cp.features - ?.singleOrNull { it is TaintConfigurationFeature } - ?.let { it as TaintConfigurationFeature } - } - - override fun obtainPossibleStartFacts( + fun obtainPossibleStartFacts( method: JcMethod, ): Collection = buildSet { addAll(obtainPossibleStartFactsBasic(method)) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt index 99937b6bf..6ba569f4c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt @@ -19,6 +19,7 @@ package org.jacodb.analysis.taint import org.jacodb.analysis.config.CallPositionToJcValueResolver import org.jacodb.analysis.config.FactAwareConditionEvaluator import org.jacodb.analysis.ifds.Analyzer +import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr @@ -29,21 +30,31 @@ import org.jacodb.taint.configuration.TaintMethodSink private val logger = mu.KotlinLogging.logger {} + class TaintAnalyzer( private val graph: JcApplicationGraph, ) : Analyzer { + private val cp = graph.classpath - override val flowFunctions: ForwardTaintFlowFunctions by lazy { - ForwardTaintFlowFunctions(graph.classpath, graph) + private val taintConfigurationFeature: TaintConfigurationFeature? by lazy { + cp.features + ?.singleOrNull { it is TaintConfigurationFeature } + ?.let { it as TaintConfigurationFeature } } - private val taintConfigurationFeature: TaintConfigurationFeature? - get() = flowFunctions.taintConfigurationFeature + + override val flowFunctions: ForwardTaintFlowFunctions by lazy { + ForwardTaintFlowFunctions(cp, graph, taintConfigurationFeature) + } private fun isExitPoint(statement: JcInst): Boolean { return statement in graph.exitPoints(statement.location.method) } + override fun obtainPossibleStartFacts( + method: JcMethod, + ): Collection = flowFunctions.obtainPossibleStartFacts(method) + override fun handleNewEdge( edge: TaintEdge, ): List = buildList { @@ -90,6 +101,12 @@ class BackwardTaintAnalyzer( BackwardTaintFlowFunctions(graph.classpath, graph) } + override fun obtainPossibleStartFacts( + method: JcMethod, + ): Collection { + return listOf(TaintZeroFact) + } + private fun isExitPoint(statement: JcInst): Boolean { return statement in graph.exitPoints(statement.location.method) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt index 3d95fb23f..a6ef8f1a4 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt @@ -60,15 +60,10 @@ private val logger = mu.KotlinLogging.logger {} class ForwardTaintFlowFunctions( private val cp: JcClasspath, private val graph: JcApplicationGraph, + private val taintConfigurationFeature: TaintConfigurationFeature?, ) : FlowFunctions { - internal val taintConfigurationFeature: TaintConfigurationFeature? by lazy { - cp.features - ?.singleOrNull { it is TaintConfigurationFeature } - ?.let { it as TaintConfigurationFeature } - } - - override fun obtainPossibleStartFacts( + fun obtainPossibleStartFacts( method: JcMethod, ): Collection = buildSet { // Zero (reachability) fact always present at entrypoint: @@ -441,8 +436,7 @@ class BackwardTaintFlowFunctions( private val project: JcClasspath, private val graph: JcApplicationGraph, ) : FlowFunctions { - - override fun obtainPossibleStartFacts( + fun obtainPossibleStartFacts( method: JcMethod, ): Collection { return listOf(TaintZeroFact) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt index 1f1425c6b..5321cf9f3 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt @@ -17,6 +17,7 @@ package org.jacodb.analysis.unused import org.jacodb.analysis.ifds.Analyzer +import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge @@ -29,6 +30,9 @@ class UnusedVariableAnalyzer( UnusedVariableFlowFunctions(graph) } + override fun obtainPossibleStartFacts(method: JcMethod): Collection = + setOf(UnusedVariableZeroFact) + private fun isExitPoint(statement: JcInst): Boolean { return statement in graph.exitPoints(statement.location.method) } @@ -38,5 +42,4 @@ class UnusedVariableAnalyzer( add(NewSummaryEdge(edge)) } } - } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt index 287bd7df8..e8a6a5f4a 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt @@ -35,12 +35,6 @@ class UnusedVariableFlowFunctions( private val cp: JcClasspath get() = graph.classpath - override fun obtainPossibleStartFacts( - method: JcMethod, - ): Collection { - return setOf(UnusedVariableZeroFact) - } - override fun sequent( current: JcInst, next: JcInst, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt index 6d6f43601..5d48f5268 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt @@ -53,7 +53,7 @@ class DefaultAnalyzer( } is NotificationOnStart -> { - val scope = JcFlowScope(message.edge, this) + val scope = JcFlowScope(message.summaryEdge, this) scope.processNotificationOnStart(message) } @@ -114,11 +114,11 @@ class DefaultAnalyzer( private fun JcFlowScope.processNotificationOnStart(message: NotificationOnStart) { - val successors = applicationGraph.successors(message.data.to.statement) + val successors = applicationGraph.successors(message.subscribingEdge.to.statement) flowFunctions.run { for (successor in successors) { - exitToReturnSite(message.data, successor) + exitToReturnSite(message.subscribingEdge, successor) } } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt index 2b33e4274..0586591e0 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -30,14 +30,13 @@ import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.mergeIfdsResults -import org.jacodb.ifds.taint.TaintVulnerability import org.jacodb.impl.features.usagesExt suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) val npeAnalyzer = NpeAnalyzer(graph) - for (fact in npeAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { + for (fact in npeAnalyzer.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { val vertex = Vertex(entryPoint, fact) val message = NewEdge(SingletonRunnerId, Edge(vertex, vertex), Reason.Initial) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index e4e93ef9f..458450e6f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -37,7 +37,7 @@ suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) val taintAnalyzer = TaintAnalyzer(graph) - for (fact in taintAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { + for (fact in taintAnalyzer.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { val vertex = Vertex(entryPoint, fact) val message = NewEdge(ForwardRunnerId, Edge(vertex, vertex), Reason.Initial) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt index 3f320b83d..dc68a4a42 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -40,7 +40,7 @@ suspend fun ActorSystem.startUnusedAnalysis(method: JcMethod) { val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) val unusedAnalyzer = UnusedVariableAnalyzer(graph) - for (fact in unusedAnalyzer.flowFunctions.obtainPossibleStartFacts(method)) { + for (fact in unusedAnalyzer.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { val vertex = Vertex(entryPoint, fact) val message = NewEdge(SingletonRunnerId, Edge(vertex, vertex), Reason.Initial) diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt index 03e477e41..7192bbe3b 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt @@ -55,15 +55,14 @@ class TaintFlowFunctionsTest : BaseTest() { companion object : WithDB(Usages, InMemoryHierarchy) - override val cp: JcClasspath = runBlocking { + private val configurationFeature = run { val configFileName = "config_test.json" val configResource = this.javaClass.getResourceAsStream("/$configFileName") if (configResource != null) { val configJson = configResource.bufferedReader().readText() - val configurationFeature = TaintConfigurationFeature.fromJson(configJson) - db.classpath(allClasspath, listOf(configurationFeature) + classpathFeatures) + TaintConfigurationFeature.fromJson(configJson) } else { - super.cp + null } } @@ -98,7 +97,8 @@ class TaintFlowFunctionsTest : BaseTest() { @Test fun `test obtain start facts`() { - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) + val flowSpace = + ForwardTaintFlowFunctions(cp, graph, configurationFeature) val facts = flowSpace.obtainPossibleStartFacts(testMethod).toList() val arg0 = cp.getArgument(testMethod.parameters[0])!! val arg0Taint = Tainted(arg0.toPath(), TaintMark("EXAMPLE")) @@ -111,7 +111,7 @@ class TaintFlowFunctionsTest : BaseTest() { val x: JcLocal = JcLocalVar(1, "x", stringType) val y: JcLocal = JcLocalVar(2, "y", stringType) val inst = JcAssignInst(location = mockk(), lhv = x, rhv = y) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val facts = flowSpace.sequent(inst, next = mockk(), yTaint).toList() @@ -127,7 +127,7 @@ class TaintFlowFunctionsTest : BaseTest() { every { method } returns testMethod } }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("EXAMPLE")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), TaintZeroFact).toList() Assertions.assertEquals(listOf(TaintZeroFact, xTaint), facts) @@ -143,7 +143,7 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("REMOVE")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() Assertions.assertTrue(facts.isEmpty()) @@ -160,7 +160,7 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("COPY")) val yTaint = Tainted(y.toPath(), TaintMark("COPY")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() @@ -181,7 +181,7 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val arg0: JcArgument = cp.getArgument(testMethod.parameters[0])!! @@ -220,10 +220,10 @@ class TaintFlowFunctionsTest : BaseTest() { val exitStatement = JcReturnInst(location = mockk { every { method } returns testMethod }, returnValue = y) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) - val facts = flowSpace.exitToReturnSite(callStatement, returnSite = mockk(), exitStatement, yTaint) + val facts = flowSpace.exitToReturnSite(callStatement, returnSite = mockk(), exitStatement, yTaint).toList() Assertions.assertEquals(listOf(xTaint), facts) } } From 3b7431ee717873be8e51688f61547c8ea1832bb6 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 14:16:34 +0300 Subject: [PATCH 36/64] [ifds] wip: renamings --- .../main/kotlin/org/jacodb/ifds/ChunkResolver.kt | 6 +++--- .../org/jacodb/ifds/actors/ProjectManager.kt | 16 ++++++++-------- .../org/jacodb/ifds/actors/RunnerStorage.kt | 12 ++++++------ .../main/kotlin/org/jacodb/ifds/actors/Worker.kt | 2 +- .../kotlin/org/jacodb/ifds/domain/Analyzer.kt | 3 +-- .../org/jacodb/ifds/messages/ProjectMessages.kt | 2 +- .../org/jacodb/ifds/messages/StorageMessages.kt | 10 +++++----- .../ifds/result/{IfdsResult.kt => Finding.kt} | 2 +- .../jacodb/ifds/result/IfdsComputationData.kt | 4 ++-- .../kotlin/org/jacodb/ifds/result/Merging.kt | 12 ++++++------ .../kotlin/org/jacodb/ifds/DefaultAnalyzer.kt | 2 +- .../main/kotlin/org/jacodb/ifds/npe/Results.kt | 4 ++-- .../org/jacodb/ifds/npe/SystemExtensions.kt | 6 +++--- .../main/kotlin/org/jacodb/ifds/taint/Results.kt | 4 ++-- .../org/jacodb/ifds/taint/SystemExtensions.kt | 6 +++--- .../kotlin/org/jacodb/ifds/unused/Results.kt | 4 ++-- .../org/jacodb/ifds/unused/SystemExtensions.kt | 4 ++-- .../org/jacodb/analysis/impl/BaseAnalysisTest.kt | 4 ++-- .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 4 ++-- 19 files changed, 53 insertions(+), 54 deletions(-) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/{IfdsResult.kt => Finding.kt} (95%) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt index 6e902f405..58e1f19d4 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt @@ -25,7 +25,7 @@ import org.jacodb.ifds.messages.NewResult import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.messages.NotificationOnEnd import org.jacodb.ifds.messages.NotificationOnStart -import org.jacodb.ifds.messages.ObtainData +import org.jacodb.ifds.messages.CollectData import org.jacodb.ifds.messages.ResolvedCall import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.StorageMessage @@ -105,8 +105,8 @@ class DefaultChunkResolver( chunkStrategy.chunkByStmt(message.edge.to.statement) } - is ObtainData<*, *, *> -> { - message as ObtainData + is CollectData<*, *, *> -> { + message as CollectData message.chunk } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt index db7a17fdb..79ce6a38d 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt @@ -16,20 +16,20 @@ package org.jacodb.ifds.actors -import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.CompletableDeferred import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.impl.routing.messageKeyRouter import org.jacodb.ifds.IfdsContext import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.messages.CollectAll +import org.jacodb.ifds.messages.CollectAllData import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewChunk -import org.jacodb.ifds.messages.ObtainData +import org.jacodb.ifds.messages.CollectData import org.jacodb.ifds.messages.ProjectMessage import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.result.IfdsComputationData -import org.jacodb.ifds.result.IfdsResult +import org.jacodb.ifds.result.Finding context(ActorContext) class ProjectManager( @@ -62,13 +62,13 @@ class ProjectManager( chunks.add(message.chunk) } - is CollectAll -> { + is CollectAllData -> { val results = hashMapOf>() for (chunk in chunks) { - val channel = Channel>>() - val msg = ObtainData(chunk, message.runnerId, channel) + val ready = CompletableDeferred>>() + val msg = CollectData(chunk, message.runnerId, ready) router.send(msg) - val data = channel.receive() + val data = ready.await() results[chunk] = data } message.result.complete(results) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt index a7fa68c42..33313539f 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt @@ -29,13 +29,13 @@ import org.jacodb.ifds.messages.NewResult import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.messages.NotificationOnEnd import org.jacodb.ifds.messages.NotificationOnStart -import org.jacodb.ifds.messages.ObtainData +import org.jacodb.ifds.messages.CollectData import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.StorageMessage import org.jacodb.ifds.messages.SubscriptionOnEnd import org.jacodb.ifds.messages.SubscriptionOnStart import org.jacodb.ifds.result.IfdsComputationData -import org.jacodb.ifds.result.IfdsResult +import org.jacodb.ifds.result.Finding context(ActorContext) class RunnerStorage( @@ -59,7 +59,7 @@ class RunnerStorage( private val summaryEdgesByStart = hashMapOf, HashSet>>() private val summaryEdgesByEnd = hashMapOf, HashSet>>() - private val foundResults = hashSetOf>() + private val foundResults = hashSetOf>() override suspend fun receive(message: StorageMessage) { when (message) { @@ -131,16 +131,16 @@ class RunnerStorage( foundResults.add(message.result) } - is ObtainData<*, *, *> -> { + is CollectData<*, *, *> -> { @Suppress("UNCHECKED_CAST") - message as ObtainData> + message as CollectData> val data = IfdsComputationData( edges.groupByTo(hashMapOf()) { it.to }, edges.groupByTo(hashMapOf(), { it.to.statement }) { it.to.fact }, reasons.toMap(hashMapOf()), foundResults.toHashSet() ) - message.channel.send(data) + message.data.complete(data) } } } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt index 6a289831a..7e8b9553a 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt @@ -30,7 +30,7 @@ class Worker( ) : Actor> { override suspend fun receive(message: AnalyzerMessage) { - val newMessages = analyzer.step(message) + val newMessages = analyzer.handle(message) for (newMessage in newMessages) { parent.send(newMessage) } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt index 1e530ece1..ba1149f63 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt @@ -20,6 +20,5 @@ import org.jacodb.ifds.messages.AnalyzerMessage import org.jacodb.ifds.messages.RunnerMessage interface Analyzer { - // TODO: consider 'handle' - fun step(message: AnalyzerMessage): Collection + fun handle(message: AnalyzerMessage): Collection } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt index 2d7cec961..f79fb52de 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt @@ -27,7 +27,7 @@ data class NewChunk( val chunk: Chunk, ) : ProjectMessage -data class CollectAll( +data class CollectAllData( val runnerId: RunnerId, val result: CompletableDeferred>>, ) : ProjectMessage diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt index c314125bc..596fefcb5 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt @@ -16,14 +16,14 @@ package org.jacodb.ifds.messages -import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.CompletableDeferred import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.IfdsComputationData -import org.jacodb.ifds.result.IfdsResult +import org.jacodb.ifds.result.Finding sealed interface StorageMessage : RunnerMessage @@ -54,11 +54,11 @@ data class SubscriptionOnEnd( data class NewResult( override val runnerId: RunnerId, - val result: IfdsResult, + val result: Finding, ) : StorageMessage -data class ObtainData>( +data class CollectData>( val chunk: Chunk, override val runnerId: RunnerId, - val channel: Channel>, + val data: CompletableDeferred>, ) : StorageMessage diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Finding.kt similarity index 95% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Finding.kt index 844c07d22..ffb9db748 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsResult.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Finding.kt @@ -18,6 +18,6 @@ package org.jacodb.ifds.result import org.jacodb.ifds.domain.Vertex -interface IfdsResult { +interface Finding { val vertex: Vertex } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt index 4ed7c5dfc..e6e92331c 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt @@ -23,9 +23,9 @@ import org.jacodb.ifds.domain.Vertex /** * Aggregates all facts and edges found by the tabulation algorithm. */ -data class IfdsComputationData>( +data class IfdsComputationData>( val edgesByEnd: Map, Collection>>, val facts: Map>, val reasons: Map, Collection>>, - val results: Collection, + val findings: Collection, ) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt index bcf06581c..13f2338c9 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt @@ -20,13 +20,13 @@ import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex -fun > mergeIfdsResults( - ifdsResults: Collection>, -): IfdsComputationData { +fun > mergeIfdsResults( + ifdsResults: Collection>, +): IfdsComputationData { val edgesByEnd = hashMapOf, HashSet>>() val factsByStmt = hashMapOf>() val reasonsByEdge = hashMapOf, HashSet>>() - val results = hashSetOf() + val findings = hashSetOf() for (data in ifdsResults) { for ((end, edges) in data.edgesByEnd) { edgesByEnd.getOrPut(end, ::hashSetOf) @@ -40,13 +40,13 @@ fun > mergeIfdsResults( reasonsByEdge.getOrPut(edge, ::hashSetOf) .addAll(reasons) } - results.addAll(data.results) + findings.addAll(data.findings) } val mergedData = IfdsComputationData( edgesByEnd, factsByStmt, reasonsByEdge, - results + findings ) return mergedData } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt index 5d48f5268..a0e92bc3e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt @@ -39,7 +39,7 @@ class DefaultAnalyzer( private val flowFunctions: FlowFunctions, private val runnerId: RunnerId, ) : Analyzer { - override fun step(message: AnalyzerMessage): Collection = buildList { + override fun handle(message: AnalyzerMessage): Collection = buildList { when (message) { is EdgeMessage -> { val scope = JcFlowScope(message.edge, this) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt index 31dd1782e..b2a2edb7c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt @@ -20,14 +20,14 @@ import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.analysis.taint.TaintVertex import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.result.IfdsResult +import org.jacodb.ifds.result.Finding import org.jacodb.taint.configuration.TaintMethodSink data class NpeVulnerability( val message: String, val sink: TaintVertex, val rule: TaintMethodSink? = null, -) : IfdsResult { +) : Finding { override val vertex: Vertex get() = sink } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt index 0586591e0..76a666c9a 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -25,7 +25,7 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.CollectAll +import org.jacodb.ifds.messages.CollectAllData import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData @@ -47,11 +47,11 @@ suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { suspend fun ActorSystem.collectNpeResults(): Collection = collectNpeComputationData() - .results + .findings suspend fun ActorSystem.collectNpeComputationData(): IfdsComputationData { - val results = ask { CollectAll(SingletonRunnerId, it) } + val results = ask { CollectAllData(SingletonRunnerId, it) } @Suppress("UNCHECKED_CAST") val ifdsData = results.values as Collection> diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt index 9fc186f28..16349f633 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt @@ -20,13 +20,13 @@ import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.analysis.taint.TaintVertex import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.result.IfdsResult +import org.jacodb.ifds.result.Finding import org.jacodb.taint.configuration.TaintMethodSink data class TaintVulnerability( val message: String, val sink: TaintVertex, val rule: TaintMethodSink? = null, -) : IfdsResult { +) : Finding { override val vertex: Vertex = sink } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index 458450e6f..418d1f450 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -25,7 +25,7 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.CollectAll +import org.jacodb.ifds.messages.CollectAllData import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData @@ -48,10 +48,10 @@ suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { suspend fun ActorSystem.collectTaintResults(): Collection = collectTaintComputationData() - .results + .findings suspend fun ActorSystem.collectTaintComputationData(): IfdsComputationData { - val results = ask { CollectAll(ForwardRunnerId, it) } + val results = ask { CollectAllData(ForwardRunnerId, it) } @Suppress("UNCHECKED_CAST") val ifdsData = results.values as Collection> diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt index 403ebf3c5..21ce5a02d 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt @@ -19,12 +19,12 @@ package org.jacodb.ifds.unused import org.jacodb.analysis.unused.UnusedVariableDomainFact import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.result.IfdsResult +import org.jacodb.ifds.result.Finding data class UnusedVulnerability( val message: String, val sink: Vertex, -) : IfdsResult { +) : Finding { override val vertex: Vertex get() = sink } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt index dc68a4a42..0175dab72 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -28,7 +28,7 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.CollectAll +import org.jacodb.ifds.messages.CollectAllData import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData @@ -77,7 +77,7 @@ suspend fun ActorSystem.collectUnusedResult(): Collection.collectUnusedComputationData(): IfdsComputationData { val results = ask { - CollectAll( + CollectAllData( SingletonRunnerId, it ) diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt index 2cf9be2ca..7d419d61e 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt @@ -24,7 +24,7 @@ import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods -import org.jacodb.ifds.result.IfdsResult +import org.jacodb.ifds.result.Finding import org.jacodb.impl.features.classpaths.UnknownClasses import org.jacodb.impl.features.hierarchyExt import org.jacodb.impl.features.usagesExt @@ -105,7 +105,7 @@ abstract class BaseAnalysisTest : BaseTest() { } } - protected fun testSingleJulietClass(className: String, findSinks: (JcMethod) -> Collection>) { + protected fun testSingleJulietClass(className: String, findSinks: (JcMethod) -> Collection>) { logger.info { className } val clazz = cp.findClass(className) diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index b226695f1..636b63fc1 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -74,7 +74,7 @@ class IfdsSqlTest : BaseAnalysisTest() { system.startTaintAnalysis(method) system.awaitCompletion() val data = system.collectTaintComputationData() - val sinks = data.results + val sinks = data.findings assertTrue(sinks.isNotEmpty()) val sink = sinks.first() val graph = data.buildTraceGraph(sink.vertex, zeroFact = TaintZeroFact) @@ -119,7 +119,7 @@ class IfdsSqlTest : BaseAnalysisTest() { system.startTaintAnalysis(badMethod) system.awaitCompletion() val data = system.collectTaintComputationData() - val sinks = data.results + val sinks = data.findings assertTrue(sinks.isNotEmpty()) val sink = sinks.first() val graph = data.buildTraceGraph(sink.vertex, zeroFact = TaintZeroFact) From ae528ee6d2339ae31281574a37057ee3086432ca Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 14:35:00 +0300 Subject: [PATCH 37/64] [ifds] wip: renamings --- .../kotlin/org/jacodb/ifds/ChunkResolver.kt | 8 +- .../org/jacodb/ifds/actors/RunnerStorage.kt | 118 +++++++++--------- .../jacodb/ifds/messages/AnalyzerMessages.kt | 14 ++- .../jacodb/ifds/messages/StorageMessages.kt | 4 +- .../org/jacodb/ifds/result/EagerTraceGraph.kt | 2 +- .../jacodb/ifds/result/IfdsComputationData.kt | 4 +- .../kotlin/org/jacodb/ifds/result/Merging.kt | 4 +- .../kotlin/org/jacodb/ifds/npe/Context.kt | 4 +- .../kotlin/org/jacodb/ifds/taint/Context.kt | 2 +- .../jacodb/ifds/unused/SystemExtensions.kt | 2 +- 10 files changed, 84 insertions(+), 78 deletions(-) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt index 58e1f19d4..ec04fed41 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt @@ -21,7 +21,7 @@ import org.jacodb.ifds.messages.AnalyzerMessage import org.jacodb.ifds.messages.EdgeMessage import org.jacodb.ifds.messages.IndirectionMessage import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.NewResult +import org.jacodb.ifds.messages.NewFinding import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.messages.NotificationOnEnd import org.jacodb.ifds.messages.NotificationOnStart @@ -95,9 +95,9 @@ class DefaultChunkResolver( chunkStrategy.chunkByStmt(message.edge.to.statement) } - is NewResult<*, *> -> { - message as NewResult - chunkStrategy.chunkByStmt(message.result.vertex.statement) + is NewFinding<*, *> -> { + message as NewFinding + chunkStrategy.chunkByStmt(message.finding.vertex.statement) } is NewSummaryEdge<*, *> -> { diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt index 33313539f..202650d59 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt @@ -23,19 +23,20 @@ import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.AnalyzerMessage +import org.jacodb.ifds.messages.CollectData import org.jacodb.ifds.messages.EdgeMessage import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.NewResult +import org.jacodb.ifds.messages.NewFinding import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.messages.NotificationOnEnd import org.jacodb.ifds.messages.NotificationOnStart -import org.jacodb.ifds.messages.CollectData import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.StorageMessage import org.jacodb.ifds.messages.SubscriptionOnEnd import org.jacodb.ifds.messages.SubscriptionOnStart -import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.Finding +import org.jacodb.ifds.result.IfdsComputationData context(ActorContext) class RunnerStorage( @@ -59,7 +60,7 @@ class RunnerStorage( private val summaryEdgesByStart = hashMapOf, HashSet>>() private val summaryEdgesByEnd = hashMapOf, HashSet>>() - private val foundResults = hashSetOf>() + private val findings = hashSetOf>() override suspend fun receive(message: StorageMessage) { when (message) { @@ -94,8 +95,27 @@ class RunnerStorage( .add(edge) // subscriptions - sendStartNotifications(edge) - sendEndNotifications(edge) + sendNotificationsOnExistingSubscribers( + startSubscribers[edge.from].orEmpty() + ) { (subscribingEdge, subscriber) -> + NotificationOnStart( + subscriber, + runnerId, + edge, + subscribingEdge + ) + + } + sendNotificationsOnExistingSubscribers( + endSubscribers[edge.to].orEmpty() + ) { (subscribingEdge, subscriber) -> + NotificationOnEnd( + subscriber, + runnerId, + edge, + subscribingEdge + ) + } } } @@ -105,7 +125,16 @@ class RunnerStorage( val savedSubscription = SavedSubscription(message.subscribingEdge, message.subscriber) - sendStartNotificationsOnExistingSummaryEdges(message.startVertex, savedSubscription) + sendNotificationsOnExistingSummaryEdges( + summaryEdgesByStart[message.startVertex].orEmpty() + ) { summaryEdge -> + NotificationOnStart( + savedSubscription.subscriber, + runnerId, + summaryEdge, + savedSubscription.edge + ) + } startSubscribers .computeIfAbsent(message.startVertex) { hashSetOf() } @@ -118,17 +147,26 @@ class RunnerStorage( val savedSubscription = SavedSubscription(message.subscribingEdge, message.subscriber) - sendEndNotificationsOnExistingSummaryEdges(message.endVertex, savedSubscription) + sendNotificationsOnExistingSummaryEdges( + summaryEdgesByEnd[message.endVertex].orEmpty() + ) { summaryEdge -> + NotificationOnEnd( + savedSubscription.subscriber, + runnerId, + summaryEdge, + savedSubscription.edge + ) + } endSubscribers .computeIfAbsent(message.endVertex) { hashSetOf() } .add(savedSubscription) } - is NewResult<*, *> -> { + is NewFinding<*, *> -> { @Suppress("UNCHECKED_CAST") - message as NewResult - foundResults.add(message.result) + message as NewFinding + findings.add(message.finding) } is CollectData<*, *, *> -> { @@ -138,67 +176,29 @@ class RunnerStorage( edges.groupByTo(hashMapOf()) { it.to }, edges.groupByTo(hashMapOf(), { it.to.statement }) { it.to.fact }, reasons.toMap(hashMapOf()), - foundResults.toHashSet() + findings.toHashSet() ) message.data.complete(data) } } } - private suspend fun sendStartNotificationsOnExistingSummaryEdges( - vertex: Vertex, - savedSubscription: SavedSubscription, + private suspend inline fun sendNotificationsOnExistingSummaryEdges( + summaries: Set>, + notificationBySummary: (Edge) -> AnalyzerMessage, ) { - val summaries = summaryEdgesByStart[vertex].orEmpty() for (summaryEdge in summaries) { - val notification = NotificationOnStart( - savedSubscription.subscriber, - runnerId, - summaryEdge, - savedSubscription.edge - ) + val notification = notificationBySummary(summaryEdge) parent.send(notification) } } - private suspend fun sendEndNotificationsOnExistingSummaryEdges( - vertex: Vertex, - savedSubscription: SavedSubscription, + private suspend inline fun sendNotificationsOnExistingSubscribers( + currentEdgeSubscribers: Set>, + notificationBySavedSubscription: (SavedSubscription) -> AnalyzerMessage, ) { - val summaries = summaryEdgesByEnd[vertex].orEmpty() - for (summaryEdge in summaries) { - val notification = NotificationOnEnd( - savedSubscription.subscriber, - runnerId, - summaryEdge, - savedSubscription.edge - ) - parent.send(notification) - } - } - - private suspend fun sendStartNotifications(edge: Edge) { - val currentEdgeStartSubscribers = startSubscribers[edge.from].orEmpty() - for ((data, subscriber) in currentEdgeStartSubscribers) { - val notification = NotificationOnStart( - subscriber, - runnerId, - edge, - data - ) - parent.send(notification) - } - } - - private suspend fun sendEndNotifications(edge: Edge) { - val currentEdgeEndSubscribers = endSubscribers[edge.to].orEmpty() - for ((data, subscriber) in currentEdgeEndSubscribers) { - val notification = NotificationOnEnd( - subscriber, - runnerId, - edge, - data - ) + for (subscription in currentEdgeSubscribers) { + val notification = notificationBySavedSubscription(subscription) parent.send(notification) } } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt index 04617add8..694b86cb3 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt @@ -33,15 +33,21 @@ data class ResolvedCall( ) : AnalyzerMessage data class NotificationOnStart( - override val runnerId: RunnerId, + val subscriber: RunnerId, val author: RunnerId, val summaryEdge: Edge, val subscribingEdge: Edge, -) : AnalyzerMessage +) : AnalyzerMessage { + override val runnerId: RunnerId + get() = subscriber +} data class NotificationOnEnd( - override val runnerId: RunnerId, + val subscriber: RunnerId, val author: RunnerId, val summaryEdge: Edge, val subscribingEdge: Edge, -) : AnalyzerMessage +) : AnalyzerMessage { + override val runnerId: RunnerId + get() = subscriber +} diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt index 596fefcb5..87e0a0071 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt @@ -52,9 +52,9 @@ data class SubscriptionOnEnd( val subscribingEdge: Edge, ) : StorageMessage -data class NewResult( +data class NewFinding( override val runnerId: RunnerId, - val result: Finding, + val finding: Finding, ) : StorageMessage data class CollectData>( diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt index ac851834d..c90a16211 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt @@ -91,7 +91,7 @@ fun IfdsComputationData.buildTraceGraph( return } - for (reason in reasons[edge].orEmpty()) { + for (reason in reasonsByEdge[edge].orEmpty()) { when (reason) { Reason.Initial -> { sources.add(vertex) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt index e6e92331c..903c3efd0 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt @@ -25,7 +25,7 @@ import org.jacodb.ifds.domain.Vertex */ data class IfdsComputationData>( val edgesByEnd: Map, Collection>>, - val facts: Map>, - val reasons: Map, Collection>>, + val factsByStmt: Map>, + val reasonsByEdge: Map, Collection>>, val findings: Collection, ) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt index 13f2338c9..871480ce2 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt @@ -32,11 +32,11 @@ fun > mergeIfdsResults( edgesByEnd.getOrPut(end, ::hashSetOf) .addAll(edges) } - for ((stmt, facts) in data.facts) { + for ((stmt, facts) in data.factsByStmt) { factsByStmt.getOrPut(stmt, ::hashSetOf) .addAll(facts) } - for ((edge, reasons) in data.reasons) { + for ((edge, reasons) in data.reasonsByEdge) { reasonsByEdge.getOrPut(edge, ::hashSetOf) .addAll(reasons) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt index 1e98ca498..d25fee798 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -27,7 +27,7 @@ import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext -import org.jacodb.ifds.messages.NewResult +import org.jacodb.ifds.messages.NewFinding import org.jacodb.ifds.messages.NewSummaryEdge fun npeIfdsContext( @@ -62,7 +62,7 @@ fun npeIfdsContext( } is NewVulnerability -> { - val result = NewResult( + val result = NewFinding( runnerId, NpeVulnerability( event.vulnerability.message, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt index 4d508f42e..958989009 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -32,7 +32,7 @@ import org.jacodb.ifds.JcIfdsContext import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.NewEdge as IfdsNewEdge -import org.jacodb.ifds.messages.NewResult as IfdsNewResult +import org.jacodb.ifds.messages.NewFinding as IfdsNewResult import org.jacodb.ifds.messages.NewSummaryEdge as IfdsNewSummaryEdge private fun complementRunner(type: RunnerId): RunnerId = diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt index 0175dab72..1ebbe2ee1 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -52,7 +52,7 @@ suspend fun ActorSystem.startUnusedAnalysis(method: JcMethod) { suspend fun ActorSystem.collectUnusedResult(): Collection { val data = collectUnusedComputationData() - val allFacts = data.facts + val allFacts = data.factsByStmt val used = hashMapOf() for ((inst, facts) in allFacts) { From 36d5c3c106c5865f7d1b4f206d5d3c11e6aa3b08 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 14:56:09 +0300 Subject: [PATCH 38/64] [ifds] wip: get rid of custom events --- .../org/jacodb/analysis/npe/NpeAnalyzers.kt | 22 ++++++----- .../jacodb/analysis/taint/TaintAnalyzers.kt | 25 ++++++++---- .../org/jacodb/analysis/taint/TaintEvents.kt | 38 ------------------- .../analysis/unused/UnusedVariableAnalyzer.kt | 10 +++-- .../analysis/unused/UnusedVariableEvents.kt | 26 ------------- .../kotlin/org/jacodb/ifds/npe/Context.kt | 29 +------------- .../org/jacodb/ifds/npe/SystemExtensions.kt | 2 +- .../kotlin/org/jacodb/ifds/taint/Context.kt | 37 +++--------------- .../org/jacodb/ifds/taint/SystemExtensions.kt | 6 +-- .../kotlin/org/jacodb/ifds/unused/Context.kt | 9 +---- .../jacodb/ifds/unused/SystemExtensions.kt | 2 +- 11 files changed, 51 insertions(+), 155 deletions(-) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt index cf399152e..4992ff014 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt @@ -19,16 +19,17 @@ package org.jacodb.analysis.npe import org.jacodb.analysis.config.CallPositionToJcValueResolver import org.jacodb.analysis.config.FactAwareConditionEvaluator import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.taint.NewSummaryEdge -import org.jacodb.analysis.taint.NewVulnerability import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.analysis.taint.TaintEdge -import org.jacodb.analysis.taint.TaintEvent import org.jacodb.analysis.taint.Tainted import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.messages.NewFinding +import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.ifds.npe.NpeVulnerability import org.jacodb.ifds.taint.TaintVulnerability import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.taint.configuration.TaintMark @@ -38,8 +39,9 @@ private val logger = mu.KotlinLogging.logger {} class NpeAnalyzer( + private val selfRunnerId: RunnerId, private val graph: JcApplicationGraph, -) : Analyzer { +) : Analyzer { val cp = graph.classpath private val taintConfigurationFeature: TaintConfigurationFeature? by lazy { @@ -62,18 +64,18 @@ class NpeAnalyzer( override fun handleNewEdge( edge: TaintEdge, - ): List = buildList { + ): List = buildList { if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(edge)) + add(org.jacodb.ifds.messages.NewSummaryEdge(selfRunnerId, edge)) } val fact = edge.to.fact if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { if (fact.variable.isDereferencedAt(edge.to.statement)) { val message = "NPE" // TODO - val vulnerability = TaintVulnerability(message, sink = edge.to) + val vulnerability = NpeVulnerability(message, sink = edge.to) logger.info { "Found sink=${vulnerability.sink} in ${vulnerability.sink.statement.location.method}" } - add(NewVulnerability(vulnerability)) + add(NewFinding(selfRunnerId, vulnerability)) } } @@ -98,8 +100,8 @@ class NpeAnalyzer( if (item.condition.accept(conditionEvaluator)) { logger.trace { "Found sink at ${edge.to} in ${edge.from.statement.location.method} on $item" } val message = item.ruleNote - val vulnerability = TaintVulnerability(message, sink = edge.to, rule = item) - add(NewVulnerability(vulnerability)) + val vulnerability = NpeVulnerability(message, sink = edge.to, rule = item) + add(NewFinding(selfRunnerId, vulnerability)) } } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt index 6ba569f4c..7b57d5fc1 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt @@ -24,6 +24,12 @@ import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.NewFinding +import org.jacodb.ifds.messages.NewSummaryEdge +import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.taint.TaintVulnerability import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.taint.configuration.TaintMethodSink @@ -31,9 +37,10 @@ import org.jacodb.taint.configuration.TaintMethodSink private val logger = mu.KotlinLogging.logger {} -class TaintAnalyzer( +class ForwardTaintAnalyzer( + private val selfRunnerId: RunnerId, private val graph: JcApplicationGraph, -) : Analyzer { +) : Analyzer { private val cp = graph.classpath private val taintConfigurationFeature: TaintConfigurationFeature? by lazy { @@ -57,9 +64,9 @@ class TaintAnalyzer( override fun handleNewEdge( edge: TaintEdge, - ): List = buildList { + ): List = buildList { if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(edge)) + add(NewSummaryEdge(selfRunnerId, edge)) } run { @@ -85,7 +92,7 @@ class TaintAnalyzer( val message = item.ruleNote val vulnerability = TaintVulnerability(message, sink = edge.to, rule = item) logger.info { "Found sink=${vulnerability.sink} in ${vulnerability.sink.statement.location.method}" } - add(NewVulnerability(vulnerability)) + add(NewFinding(selfRunnerId, vulnerability)) } } } @@ -94,8 +101,10 @@ class TaintAnalyzer( } class BackwardTaintAnalyzer( + private val selfRunnerId: RunnerId, + private val otherRunnerId: RunnerId, private val graph: JcApplicationGraph, -) : Analyzer { +) : Analyzer { override val flowFunctions: BackwardTaintFlowFunctions by lazy { BackwardTaintFlowFunctions(graph.classpath, graph) @@ -113,9 +122,9 @@ class BackwardTaintAnalyzer( override fun handleNewEdge( edge: TaintEdge, - ): List = buildList { + ): List = buildList { if (isExitPoint(edge.to.statement)) { - add(EdgeForOtherRunner(Edge(edge.to, edge.to))) + add(NewEdge(otherRunnerId, Edge(edge.to, edge.to), Reason.FromOtherRunner(edge, selfRunnerId))) } } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt deleted file mode 100644 index 0ac52ecea..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintEvents.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.taint - -import org.jacodb.ifds.taint.TaintVulnerability - -sealed interface TaintEvent - -data class NewSummaryEdge( - val edge: TaintEdge, -) : TaintEvent - -data class NewVulnerability( - val vulnerability: TaintVulnerability, -) : TaintEvent - -data class EdgeForOtherRunner( - val edge: TaintEdge, -) : TaintEvent { - init { - // TODO: remove this check - check(edge.from == edge.to) { "Edge for another runner must be a loop" } - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt index 5321cf9f3..9279b8c88 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt @@ -21,10 +21,14 @@ import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.messages.NewSummaryEdge +import org.jacodb.ifds.messages.RunnerMessage class UnusedVariableAnalyzer( + private val selfRunnerId: RunnerId, private val graph: JcApplicationGraph, -) : Analyzer { +) : Analyzer { override val flowFunctions: UnusedVariableFlowFunctions by lazy { UnusedVariableFlowFunctions(graph) @@ -37,9 +41,9 @@ class UnusedVariableAnalyzer( return statement in graph.exitPoints(statement.location.method) } - override fun handleNewEdge(edge: Edge): List = buildList { + override fun handleNewEdge(edge: Edge): List = buildList { if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(edge)) + add(NewSummaryEdge(selfRunnerId, edge)) } } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt deleted file mode 100644 index f9def48e4..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableEvents.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.unused - -import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Edge - -sealed interface Event - -data class NewSummaryEdge( - val edge: Edge, -) : Event diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt index d25fee798..7b6b4d1fb 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -17,8 +17,6 @@ package org.jacodb.ifds.npe import org.jacodb.analysis.npe.NpeAnalyzer -import org.jacodb.analysis.taint.EdgeForOtherRunner -import org.jacodb.analysis.taint.NewVulnerability import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph @@ -27,8 +25,6 @@ import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext -import org.jacodb.ifds.messages.NewFinding -import org.jacodb.ifds.messages.NewSummaryEdge fun npeIfdsContext( cp: JcClasspath, @@ -43,7 +39,7 @@ fun npeIfdsContext( chunkStrategy ) { runnerId -> val analyzer = when (runnerId) { - is SingletonRunnerId -> NpeAnalyzer(graph) + is SingletonRunnerId -> NpeAnalyzer(runnerId, graph) else -> error("Unexpected runnerId: $runnerId") } @@ -51,27 +47,6 @@ fun npeIfdsContext( runnerId, analyzer ) { event -> - when (event) { - is EdgeForOtherRunner -> { - error("Unexpected event: $event") - } - - is org.jacodb.analysis.taint.NewSummaryEdge -> { - val summaryEdge = NewSummaryEdge(runnerId, event.edge) - add(summaryEdge) - } - - is NewVulnerability -> { - val result = NewFinding( - runnerId, - NpeVulnerability( - event.vulnerability.message, - event.vulnerability.sink, - event.vulnerability.rule - ) - ) - add(result) - } - } + add(event) } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt index 76a666c9a..43dfca68f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -35,7 +35,7 @@ import org.jacodb.impl.features.usagesExt suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val npeAnalyzer = NpeAnalyzer(graph) + val npeAnalyzer = NpeAnalyzer(SingletonRunnerId, graph) for (fact in npeAnalyzer.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { val vertex = Vertex(entryPoint, fact) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt index 958989009..0e157b0d5 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -17,10 +17,7 @@ package org.jacodb.ifds.taint import org.jacodb.analysis.taint.BackwardTaintAnalyzer -import org.jacodb.analysis.taint.EdgeForOtherRunner -import org.jacodb.analysis.taint.NewSummaryEdge -import org.jacodb.analysis.taint.NewVulnerability -import org.jacodb.analysis.taint.TaintAnalyzer +import org.jacodb.analysis.taint.ForwardTaintAnalyzer import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph @@ -31,9 +28,7 @@ import org.jacodb.ifds.JcFlowFunctionsAdapter import org.jacodb.ifds.JcIfdsContext import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.NewEdge as IfdsNewEdge -import org.jacodb.ifds.messages.NewFinding as IfdsNewResult -import org.jacodb.ifds.messages.NewSummaryEdge as IfdsNewSummaryEdge +import org.jacodb.ifds.messages.NewEdge private fun complementRunner(type: RunnerId): RunnerId = when (type) { @@ -56,8 +51,8 @@ fun taintIfdsContext( chunkStrategy ) { runnerId -> val analyzer = when (runnerId) { - is ForwardRunnerId -> TaintAnalyzer(graph) - is BackwardRunnerId -> BackwardTaintAnalyzer(graph) + is ForwardRunnerId -> ForwardTaintAnalyzer(ForwardRunnerId, graph) + is BackwardRunnerId -> BackwardTaintAnalyzer(BackwardRunnerId, ForwardRunnerId, graph) else -> error("Unexpected runnerId: $runnerId") } @@ -65,28 +60,8 @@ fun taintIfdsContext( runnerId, analyzer ) { event -> - when (event) { - is EdgeForOtherRunner -> { - if (useBackwardRunner) { - val edgeForOtherRunner = - IfdsNewEdge( - complementRunner(runnerId), - event.edge, - Reason.FromOtherRunner(edge, runnerId) - ) - add(edgeForOtherRunner) - } - } - - is NewSummaryEdge -> { - val summaryEdge = IfdsNewSummaryEdge(runnerId, event.edge) - add(summaryEdge) - } - - is NewVulnerability -> { - val result = IfdsNewResult(runnerId, event.vulnerability) - add(result) - } + if (useBackwardRunner || !(event is NewEdge<*, *> && event.reason is Reason.FromOtherRunner)) { + add(event) } } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index 418d1f450..331c1be9e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -18,7 +18,7 @@ package org.jacodb.ifds.taint import org.jacodb.actors.api.ActorSystem import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.taint.TaintAnalyzer +import org.jacodb.analysis.taint.ForwardTaintAnalyzer import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst @@ -35,9 +35,9 @@ import org.jacodb.impl.features.usagesExt suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val taintAnalyzer = TaintAnalyzer(graph) + val forwardTaintAnalyzer = ForwardTaintAnalyzer(ForwardRunnerId, graph) - for (fact in taintAnalyzer.obtainPossibleStartFacts(method)) { + for (fact in forwardTaintAnalyzer.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { val vertex = Vertex(entryPoint, fact) val message = NewEdge(ForwardRunnerId, Edge(vertex, vertex), Reason.Initial) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt index 6ee012cee..915c40314 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt @@ -39,7 +39,7 @@ fun unusedIfdsContext( chunkStrategy ) { runnerId -> val analyzer = when (runnerId) { - is SingletonRunnerId -> UnusedVariableAnalyzer(graph) + is SingletonRunnerId -> UnusedVariableAnalyzer(SingletonRunnerId, graph) else -> error("Unexpected runnerId: $runnerId") } @@ -47,11 +47,6 @@ fun unusedIfdsContext( runnerId, analyzer ) { event -> - when (event) { - is org.jacodb.analysis.unused.NewSummaryEdge -> { - val edge = org.jacodb.ifds.messages.NewSummaryEdge(runnerId, event.edge) - add(edge) - } - } + add(event) } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt index 1ebbe2ee1..affdcdfc2 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -38,7 +38,7 @@ import org.jacodb.impl.features.usagesExt suspend fun ActorSystem.startUnusedAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val unusedAnalyzer = UnusedVariableAnalyzer(graph) + val unusedAnalyzer = UnusedVariableAnalyzer(SingletonRunnerId, graph) for (fact in unusedAnalyzer.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { From 554d8cf24e4eb19830aee7d06b1d571f893914a6 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 16:52:45 +0300 Subject: [PATCH 39/64] [ifds] wip: fix CLI --- .../org/jacodb/actors/api/ActorSystem.kt | 3 + .../org/jacodb/actors/impl/ActorSystemImpl.kt | 4 + .../kotlin/org/jacodb/ifds/ChunkStrategies.kt | 1 - .../kotlin/org/jacodb/ifds/npe/Context.kt | 6 +- .../org/jacodb/ifds/npe/SystemExtensions.kt | 47 +++++++++++ .../org/jacodb/ifds/sarif/Vulnerability.kt | 13 +++ .../kotlin/org/jacodb/ifds/taint/Context.kt | 6 +- .../org/jacodb/ifds/taint/SystemExtensions.kt | 78 ++++++++++++++++++ .../kotlin/org/jacodb/ifds/unused/Context.kt | 6 +- .../jacodb/ifds/unused/SystemExtensions.kt | 49 ++++++++++- .../analysis/impl/JavaAnalysisApiTest.java | 50 ++++++++---- .../org/jacodb/analysis/impl/IfdsNpeTest.kt | 4 +- .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 5 +- .../jacodb/analysis/impl/IfdsUnusedTest.kt | 8 +- .../analysis/impl/JodaDateTimeAnalysisTest.kt | 65 ++++----------- jacodb-cli/build.gradle.kts | 3 +- .../src/main/kotlin/org/jacodb/cli/main.kt | 81 ++++++++++++------- .../src/test/kotlin/org/jacodb/cli/CliTest.kt | 3 +- 18 files changed, 321 insertions(+), 111 deletions(-) diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt index f226b62d3..f315db41c 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt @@ -17,6 +17,7 @@ package org.jacodb.actors.api import kotlinx.coroutines.CompletableDeferred +import mu.KLogger interface ActorSystem { val name: String @@ -30,4 +31,6 @@ interface ActorSystem { suspend fun resume() fun stop() + + val logger: KLogger } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 037dca00d..27d5fb9b5 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -19,6 +19,8 @@ package org.jacodb.actors.impl import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob +import mu.KLogger +import mu.KotlinLogging.logger import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.api.options.SpawnOptions @@ -32,6 +34,8 @@ internal class ActorSystemImpl( ) : ActorSystem { private val path = root() / name + override val logger: KLogger = logger(path.toString()) + private val spawner = ActorSpawnerImpl(path, this) internal val scope = CoroutineScope(SupervisorJob()) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt index cd5d0e986..f5826b247 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt @@ -22,7 +22,6 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.packageName import org.jacodb.ifds.domain.Chunk -// TODO: consider 'SingletonChunk' data object SingletonChunk : Chunk val SingletonChunkStrategy = ChunkStrategy { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt index 7b6b4d1fb..4469aee33 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -20,7 +20,9 @@ import org.jacodb.analysis.npe.NpeAnalyzer import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.ChunkResolver +import org.jacodb.ifds.ChunkStrategy import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter @@ -30,13 +32,13 @@ fun npeIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List, - chunkStrategy: ChunkResolver = DefaultChunkResolver(ClassChunkStrategy), + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsContext = JcIfdsContext( cp, graph, bannedPackagePrefixes, - chunkStrategy + DefaultChunkResolver(chunkStrategy) ) { runnerId -> val analyzer = when (runnerId) { is SingletonRunnerId -> NpeAnalyzer(runnerId, graph) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt index 43dfca68f..99e2704d2 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -16,12 +16,22 @@ package org.jacodb.ifds.npe +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import org.jacodb.actors.api.ActorSystem +import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.npe.NpeAnalyzer import org.jacodb.analysis.taint.TaintDomainFact +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.ifds.ChunkStrategy +import org.jacodb.ifds.ClassChunkStrategy +import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex @@ -31,6 +41,43 @@ import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.mergeIfdsResults import org.jacodb.impl.features.usagesExt +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +fun npeIfdsSystem( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): ActorSystem { + val context = npeIfdsContext( + cp, + graph, + bannedPackagePrefixes, + chunkStrategy + ) + return system(name) { + ProjectManager(context) + } +} + +suspend fun ActorSystem.runNpeAnalysis( + methods: Collection, + timeout: Duration = 60.seconds, +): Unit = coroutineScope { + for (method in methods) { + startNpeAnalysis(method) + } + val stopper = launch { + delay(timeout) + logger.info { "Timeout! Stopping the system..." } + stop() + } + awaitCompletion() + stopper.cancel() + resume() +} suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt index 21ecef503..5ee0ac851 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt @@ -20,6 +20,7 @@ import io.github.detekt.sarif4k.Level import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.analysis.unused.UnusedVariableDomainFact import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.npe.NpeVulnerability import org.jacodb.ifds.result.EagerTraceGraph import org.jacodb.ifds.result.TraceGraph import org.jacodb.ifds.taint.TaintVulnerability @@ -54,3 +55,15 @@ fun TaintVulnerability.toSarif( ) ) } + +fun NpeVulnerability.toSarif( + graph: TraceGraph, +): VulnerabilityInstance { + return VulnerabilityInstance( + graph, + VulnerabilityDescription( + ruleId = null, + message = this.rule?.ruleNote + ) + ) +} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt index 0e157b0d5..510d5da74 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -21,7 +21,9 @@ import org.jacodb.analysis.taint.ForwardTaintAnalyzer import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.ChunkResolver +import org.jacodb.ifds.ChunkStrategy import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter @@ -41,14 +43,14 @@ fun taintIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List, - chunkStrategy: ChunkResolver = DefaultChunkResolver(ClassChunkStrategy), + chunkStrategy: ChunkStrategy = ClassChunkStrategy, useBackwardRunner: Boolean = false, ): JcIfdsContext = JcIfdsContext( cp, graph, bannedPackagePrefixes, - chunkStrategy + DefaultChunkResolver(chunkStrategy) ) { runnerId -> val analyzer = when (runnerId) { is ForwardRunnerId -> ForwardTaintAnalyzer(ForwardRunnerId, graph) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index 331c1be9e..52ba86d32 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -16,12 +16,25 @@ package org.jacodb.ifds.taint +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.future.future +import kotlinx.coroutines.launch import org.jacodb.actors.api.ActorSystem +import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.taint.ForwardTaintAnalyzer import org.jacodb.analysis.taint.TaintDomainFact +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.ifds.ChunkStrategy +import org.jacodb.ifds.ClassChunkStrategy +import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex @@ -31,6 +44,52 @@ import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.mergeIfdsResults import org.jacodb.impl.features.usagesExt +import java.util.concurrent.CompletableFuture +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +fun taintIfdsSystem( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): ActorSystem { + val context = taintIfdsContext( + cp, + graph, + bannedPackagePrefixes, + chunkStrategy + ) + return system(name) { + ProjectManager(context) + } +} + +suspend fun ActorSystem.runTaintAnalysis( + methods: Collection, + timeout: Duration = 60.seconds, +): Unit = coroutineScope { + for (method in methods) { + startTaintAnalysis(method) + } + val stopper = launch { + delay(timeout) + logger.info { "Timeout! Stopping the system..." } + stop() + } + awaitCompletion() + stopper.cancel() + resume() +} + +@OptIn(DelicateCoroutinesApi::class) +fun ActorSystem.runTaintAnalysisAsync( + methods: Collection, + timeout: Duration = 60.seconds, +): CompletableFuture = GlobalScope.future { + runTaintAnalysis(methods, timeout) +} suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath @@ -46,10 +105,23 @@ suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { } } +@OptIn(DelicateCoroutinesApi::class) +fun ActorSystem.startTaintAnalysisAsync( + method: JcMethod, +): CompletableFuture = GlobalScope.future { + startTaintAnalysis(method) +} + suspend fun ActorSystem.collectTaintResults(): Collection = collectTaintComputationData() .findings +@OptIn(DelicateCoroutinesApi::class) +fun ActorSystem.collectTaintResultsAsync(): CompletableFuture> = + GlobalScope.future { + collectTaintResults() + } + suspend fun ActorSystem.collectTaintComputationData(): IfdsComputationData { val results = ask { CollectAllData(ForwardRunnerId, it) } @@ -58,3 +130,9 @@ suspend fun ActorSystem.collectTaintComputationData(): IfdsComput return mergeIfdsResults(ifdsData) } + +@OptIn(DelicateCoroutinesApi::class) +fun ActorSystem.collectTaintComputationDataAsync(): CompletableFuture> = + GlobalScope.future { + collectTaintComputationData() + } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt index 915c40314..1211884ea 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt @@ -20,7 +20,9 @@ import org.jacodb.analysis.unused.UnusedVariableAnalyzer import org.jacodb.analysis.unused.UnusedVariableDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.ChunkResolver +import org.jacodb.ifds.ChunkStrategy import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver import org.jacodb.ifds.JcFlowFunctionsAdapter @@ -30,13 +32,13 @@ fun unusedIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List, - chunkStrategy: ChunkResolver = DefaultChunkResolver(ClassChunkStrategy), + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsContext = JcIfdsContext( cp, graph, bannedPackagePrefixes, - chunkStrategy + DefaultChunkResolver(chunkStrategy) ) { runnerId -> val analyzer = when (runnerId) { is SingletonRunnerId -> UnusedVariableAnalyzer(SingletonRunnerId, graph) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt index affdcdfc2..2dfcbf496 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -16,15 +16,25 @@ package org.jacodb.ifds.unused +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import org.jacodb.actors.api.ActorSystem +import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.unused.UnusedVariable import org.jacodb.analysis.unused.UnusedVariableAnalyzer import org.jacodb.analysis.unused.UnusedVariableDomainFact import org.jacodb.analysis.unused.UnusedVariableZeroFact import org.jacodb.analysis.unused.isUsedAt +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.ifds.ChunkStrategy +import org.jacodb.ifds.ClassChunkStrategy +import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.Vertex @@ -34,6 +44,43 @@ import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.mergeIfdsResults import org.jacodb.impl.features.usagesExt +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +fun unusedIfdsSystem( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): ActorSystem { + val context = unusedIfdsContext( + cp, + graph, + bannedPackagePrefixes, + chunkStrategy + ) + return system(name) { + ProjectManager(context) + } +} + +suspend fun ActorSystem.runUnusedAnalysis( + methods: Collection, + timeout: Duration = 60.seconds, +): Unit = coroutineScope { + for (method in methods) { + startUnusedAnalysis(method) + } + val stopper = launch { + delay(timeout) + logger.info { "Timeout! Stopping the system..." } + stop() + } + awaitCompletion() + stopper.cancel() + resume() +} suspend fun ActorSystem.startUnusedAnalysis(method: JcMethod) { val cp = method.enclosingClass.classpath @@ -49,7 +96,7 @@ suspend fun ActorSystem.startUnusedAnalysis(method: JcMethod) { } } -suspend fun ActorSystem.collectUnusedResult(): Collection { +suspend fun ActorSystem.collectUnusedResults(): Collection { val data = collectUnusedComputationData() val allFacts = data.factsByStmt diff --git a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java index 2b36c5828..19a8487c4 100644 --- a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java +++ b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java @@ -16,10 +16,17 @@ package org.jacodb.analysis.impl; +import kotlin.Unit; +import kotlin.time.DurationUnit; +import org.jacodb.actors.api.ActorSystem; import org.jacodb.analysis.graph.ApplicationGraphFactory; +import org.jacodb.api.JcClassOrInterface; import org.jacodb.api.JcClasspath; import org.jacodb.api.JcDatabase; +import org.jacodb.api.JcMethod; import org.jacodb.api.analysis.JcApplicationGraph; +import org.jacodb.ifds.ChunkStrategiesKt; +import org.jacodb.ifds.messages.CommonMessage; import org.jacodb.impl.JacoDB; import org.jacodb.impl.JcSettings; import org.jacodb.impl.features.InMemoryHierarchy; @@ -31,8 +38,14 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import static kotlin.time.DurationKt.toDuration; +import static org.jacodb.analysis.graph.ApplicationGraphFactory.getDefaultBannedPackagePrefixes; +import static org.jacodb.ifds.taint.SystemExtensionsKt.runTaintAnalysisAsync; +import static org.jacodb.ifds.taint.SystemExtensionsKt.taintIfdsSystem; + public class JavaAnalysisApiTest { private static JcClasspath classpath; @@ -43,21 +56,28 @@ public static void initClasspath() throws ExecutionException, InterruptedExcepti classpath = instance.asyncClasspath(LibrariesMixinKt.getAllClasspath()).get(); } -// TODO: fix test -// -// @Test -// public void testJavaAnalysisApi() throws ExecutionException, InterruptedException { -// JcClassOrInterface analyzedClass = classpath.findClassOrNull("org.jacodb.testing.analysis.NpeExamples"); -// Assertions.assertNotNull(analyzedClass); -// -// List methodsToAnalyze = analyzedClass.getDeclaredMethods(); -// JcApplicationGraph applicationGraph = ApplicationGraphFactory -// .newApplicationGraphForAnalysisAsync(classpath, null) -// .get(); -// UnitResolver unitResolver = UnitResolverKt.getMethodUnitResolver(); -// TaintManager manager = new TaintManager(applicationGraph, unitResolver, false); -// manager.analyze(methodsToAnalyze, toDuration(30, DurationUnit.SECONDS)); -// } + @Test + public void testJavaAnalysisApi() throws ExecutionException, InterruptedException { + JcClassOrInterface analyzedClass = classpath.findClassOrNull("org.jacodb.testing.analysis.NpeExamples"); + Assertions.assertNotNull(analyzedClass); + + List methodsToAnalyze = analyzedClass.getDeclaredMethods(); + JcApplicationGraph applicationGraph = ApplicationGraphFactory + .newApplicationGraphForAnalysisAsync(classpath, null) + .get(); + + ActorSystem system = taintIfdsSystem( + "ifds", + applicationGraph.getClasspath(), + applicationGraph, + getDefaultBannedPackagePrefixes(), + ChunkStrategiesKt.getClassChunkStrategy()); + CompletableFuture future = runTaintAnalysisAsync( + system, + methodsToAnalyze, + toDuration(30, DurationUnit.SECONDS)); + future.get(); + } @Test public void testCustomBannedPackagesApi() throws ExecutionException, InterruptedException { diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt index 1bd7d7983..e6a273587 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt @@ -27,6 +27,7 @@ import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.npe.NpeVulnerability import org.jacodb.ifds.npe.collectNpeResults import org.jacodb.ifds.npe.npeIfdsContext +import org.jacodb.ifds.npe.npeIfdsSystem import org.jacodb.ifds.npe.startNpeAnalysis import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages @@ -199,8 +200,7 @@ class IfdsNpeTest : BaseAnalysisTest() { } private fun findSinks(method: JcMethod): Collection = runBlocking { - val ifdsContext = npeIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = system("ifds") { ProjectManager(ifdsContext) } + val system = npeIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) system.startNpeAnalysis(method) system.awaitCompletion() diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index 636b63fc1..f8a7a6aa3 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -34,6 +34,7 @@ import org.jacodb.ifds.taint.collectTaintComputationData import org.jacodb.ifds.taint.collectTaintResults import org.jacodb.ifds.taint.startTaintAnalysis import org.jacodb.ifds.taint.taintIfdsContext +import org.jacodb.ifds.taint.taintIfdsSystem import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.testing.WithDB @@ -83,8 +84,7 @@ class IfdsSqlTest : BaseAnalysisTest() { } private fun findSinks(method: JcMethod): Collection = runBlocking { - val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = system("ifds") { ProjectManager(ifdsContext) } + val system = taintIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) system.startTaintAnalysis(method) system.awaitCompletion() @@ -118,6 +118,7 @@ class IfdsSqlTest : BaseAnalysisTest() { system.startTaintAnalysis(badMethod) system.awaitCompletion() + val data = system.collectTaintComputationData() val sinks = data.findings assertTrue(sinks.isNotEmpty()) diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt index b8f8d1166..82b323cb2 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt @@ -24,9 +24,10 @@ import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.unused.UnusedVulnerability -import org.jacodb.ifds.unused.collectUnusedResult +import org.jacodb.ifds.unused.collectUnusedResults import org.jacodb.ifds.unused.startUnusedAnalysis import org.jacodb.ifds.unused.unusedIfdsContext +import org.jacodb.ifds.unused.unusedIfdsSystem import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.testing.WithDB @@ -62,12 +63,11 @@ class IfdsUnusedTest : BaseAnalysisTest() { } private fun findSinks(method: JcMethod): Collection = runBlocking { - val ifdsContext = unusedIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = system("ifds") { ProjectManager(ifdsContext) } + val system = unusedIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) system.startUnusedAnalysis(method) system.awaitCompletion() - system.collectUnusedResult() + system.collectUnusedResults() } @ParameterizedTest diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt index ed997cb11..089069353 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt @@ -16,25 +16,21 @@ package org.jacodb.analysis.impl -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking -import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.ext.findClass -import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.npe.collectNpeResults -import org.jacodb.ifds.npe.npeIfdsContext -import org.jacodb.ifds.npe.startNpeAnalysis +import org.jacodb.ifds.npe.npeIfdsSystem +import org.jacodb.ifds.npe.runNpeAnalysis import org.jacodb.ifds.taint.collectTaintResults -import org.jacodb.ifds.taint.startTaintAnalysis -import org.jacodb.ifds.taint.taintIfdsContext -import org.jacodb.ifds.unused.collectUnusedResult -import org.jacodb.ifds.unused.startUnusedAnalysis -import org.jacodb.ifds.unused.unusedIfdsContext +import org.jacodb.ifds.taint.runTaintAnalysis +import org.jacodb.ifds.taint.taintIfdsSystem +import org.jacodb.ifds.unused.collectUnusedResults +import org.jacodb.ifds.unused.runUnusedAnalysis +import org.jacodb.ifds.unused.unusedIfdsSystem import org.jacodb.impl.features.usagesExt import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.testing.BaseTest @@ -70,64 +66,31 @@ class JodaDateTimeAnalysisTest : BaseTest() { @Test fun `test taint analysis`() = runBlocking { + val system = taintIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) val clazz = cp.findClass() val methods = clazz.declaredMethods - - val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = system("ifds") { ProjectManager(ifdsContext) } - - for (method in methods) { - system.startTaintAnalysis(method) - } - val stopper = launch { - delay(20.seconds) - logger.info { "Timeout! Stopping the system..." } - system.stop() - } - system.awaitCompletion() - stopper.cancel() - system.resume() - + system.runTaintAnalysis(methods, timeout = 20.seconds) val sinks = system.collectTaintResults() logger.info { "Vulnerabilities found: ${sinks.size}" } } @Test fun `test NPE analysis`() = runBlocking { + val system = npeIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) val clazz = cp.findClass() val methods = clazz.declaredMethods - val ifdsContext = npeIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = system("ifds") { ProjectManager(ifdsContext) } - - for (method in methods) { - system.startNpeAnalysis(method) - } - val stopper = launch { - delay(20.seconds) - logger.info { "Timeout! Stopping the system..." } - system.stop() - } - system.awaitCompletion() - stopper.cancel() - system.resume() - + system.runNpeAnalysis(methods, timeout = 20.seconds) val sinks = system.collectNpeResults() logger.info { "Vulnerabilities found: ${sinks.size}" } } @Test fun `test unused variables analysis`() = runBlocking { + val system = unusedIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) val clazz = cp.findClass() val methods = clazz.declaredMethods - val ifdsContext = unusedIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = system("ifds") { ProjectManager(ifdsContext) } - - for (method in methods) { - system.startUnusedAnalysis(method) - } - system.awaitCompletion() - val sinks = system.collectUnusedResult() - + system.runUnusedAnalysis(methods, timeout = 20.seconds) + val sinks = system.collectUnusedResults() logger.info { "Vulnerabilities found: ${sinks.size}" } } } diff --git a/jacodb-cli/build.gradle.kts b/jacodb-cli/build.gradle.kts index 56a8dfec6..f675ff24b 100644 --- a/jacodb-cli/build.gradle.kts +++ b/jacodb-cli/build.gradle.kts @@ -4,7 +4,8 @@ plugins { dependencies { api(project(":jacodb-core")) - api(project(":jacodb-analysis")) + api(project(":jacodb-analysis:taint")) + api(project(":jacodb-analysis:ifds")) api(project(":jacodb-api")) implementation(Libs.kotlin_logging) diff --git a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt index 2bbee2bbc..923ff591c 100644 --- a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt +++ b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt @@ -26,22 +26,32 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.encodeToStream -import org.jacodb.analysis.graph.newApplicationGraphForAnalysis -import org.jacodb.analysis.ifds.SingletonUnitResolver -import org.jacodb.analysis.ifds.UnitResolver -import org.jacodb.analysis.npe.NpeManager -import org.jacodb.analysis.sarif.VulnerabilityInstance -import org.jacodb.analysis.sarif.sarifReportFromVulnerabilities -import org.jacodb.analysis.taint.TaintManager -import org.jacodb.analysis.taint.toSarif -import org.jacodb.analysis.unused.UnusedVariableManager -import org.jacodb.analysis.unused.toSarif +import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.taint.TaintZeroFact import org.jacodb.api.JcClassOrInterface import org.jacodb.api.JcClassProcessingTask import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.ClassChunkStrategy +import org.jacodb.ifds.MethodChunkStrategy +import org.jacodb.ifds.PackageChunkStrategy +import org.jacodb.ifds.SingletonChunkStrategy +import org.jacodb.ifds.npe.collectNpeComputationData +import org.jacodb.ifds.npe.npeIfdsSystem +import org.jacodb.ifds.npe.runNpeAnalysis +import org.jacodb.ifds.result.buildTraceGraph +import org.jacodb.ifds.sarif.VulnerabilityInstance +import org.jacodb.ifds.sarif.sarifReportFromVulnerabilities +import org.jacodb.ifds.sarif.toSarif +import org.jacodb.ifds.taint.collectTaintComputationData +import org.jacodb.ifds.taint.runTaintAnalysis +import org.jacodb.ifds.taint.taintIfdsSystem +import org.jacodb.ifds.unused.collectUnusedResults +import org.jacodb.ifds.unused.unusedIfdsSystem 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.concurrent.ConcurrentHashMap @@ -50,7 +60,7 @@ import kotlin.time.Duration.Companion.seconds private val logger = mu.KotlinLogging.logger {} class AnalysisMain { - fun run(args: List) = main(args.toTypedArray()) + suspend fun run(args: List) = main(args.toTypedArray()) } typealias AnalysesOptions = Map @@ -58,42 +68,61 @@ typealias AnalysesOptions = Map @Serializable data class AnalysisConfig(val analyses: Map) -fun launchAnalysesByConfig( +suspend fun launchAnalysesByConfig( config: AnalysisConfig, graph: JcApplicationGraph, methods: List, -): List>> { +): List>> { return config.analyses.mapNotNull { (analysis, options) -> - val unitResolver = options["UnitResolver"]?.let { - UnitResolver.getByName(it) - } ?: SingletonUnitResolver + val chunkStrategy = options["UnitResolver"]?.let { name -> + when (name) { + "method" -> MethodChunkStrategy + "class" -> ClassChunkStrategy + "package" -> PackageChunkStrategy + "singleton" -> SingletonChunkStrategy + else -> error("Unknown unit resolver '$name'") + } + } ?: SingletonChunkStrategy when (analysis) { "NPE" -> { - val manager = NpeManager(graph, unitResolver) - manager.analyze(methods, timeout = 60.seconds).map { it.toSarif(manager.vulnerabilityTraceGraph(it)) } + val system = npeIfdsSystem("ifds", graph.classpath, graph, chunkStrategy = chunkStrategy) + system + .runNpeAnalysis(methods, timeout = 60.seconds) + val data = system.collectNpeComputationData() + data.findings.map { vulnerability -> + val traceGraph = data.buildTraceGraph(vulnerability.vertex, zeroFact = TaintZeroFact) + vulnerability.toSarif(traceGraph) + } } "Unused" -> { - val manager = UnusedVariableManager(graph, unitResolver) - manager.analyze(methods, timeout = 60.seconds).map { it.toSarif() } + val system = unusedIfdsSystem("ifds", graph.classpath, graph, chunkStrategy = chunkStrategy) + system.runNpeAnalysis(methods, timeout = 60.seconds) + system.collectUnusedResults().map { it.toSarif() } } "SQL" -> { - val manager = TaintManager(graph, unitResolver) - manager.analyze(methods, timeout = 60.seconds).map { it.toSarif(manager.vulnerabilityTraceGraph(it)) } + val system = taintIfdsSystem("ifds", graph.classpath, graph, chunkStrategy = chunkStrategy) + system + .runTaintAnalysis(methods, timeout = 60.seconds) + val data = system.collectTaintComputationData() + data.findings.map { vulnerability -> + val traceGraph = data.buildTraceGraph(vulnerability.vertex, zeroFact = TaintZeroFact) + vulnerability.toSarif(traceGraph) + } } else -> { logger.error { "Unknown analysis type: $analysis" } - return@mapNotNull null + null } } } } @OptIn(ExperimentalSerializationApi::class) -fun main(args: Array) { +suspend fun main(args: Array) { val parser = ArgParser("taint-analysis") val configFilePath by parser.option( ArgType.String, @@ -166,9 +195,7 @@ fun main(args: Array) { }).get() val startJcMethods = startJcClasses.flatMap { it.declaredMethods }.filter { !it.isPrivate } - val graph = runBlocking { - cp.newApplicationGraphForAnalysis() - } + val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) val vulnerabilities = launchAnalysesByConfig(config, graph, startJcMethods).flatten() val report = sarifReportFromVulnerabilities(vulnerabilities) diff --git a/jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt b/jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt index 3e9976978..761cc6570 100644 --- a/jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt +++ b/jacodb-cli/src/test/kotlin/org/jacodb/cli/CliTest.kt @@ -16,12 +16,13 @@ package org.jacodb.cli +import kotlinx.coroutines.runBlocking import org.jacodb.testing.analysis.NpeExamples import org.junit.jupiter.api.Test class CliTest { @Test - fun `test basic analysis cli api`() { + fun `test basic analysis cli api`() = runBlocking { val args = listOf( "-a", CliTest::class.java.getResource("/config.json")?.file ?: error("Can't find file with config"), "-s", NpeExamples::class.java.name From 753d747d0de6ba033995f96246d33face7d7b632 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 17:04:46 +0300 Subject: [PATCH 40/64] [ifds] wip: fix gradle --- jacodb-analysis/taint/build.gradle.kts | 4 ++-- jacodb-cli/build.gradle.kts | 1 - jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jacodb-analysis/taint/build.gradle.kts b/jacodb-analysis/taint/build.gradle.kts index 18d46dbd8..54cc7282e 100644 --- a/jacodb-analysis/taint/build.gradle.kts +++ b/jacodb-analysis/taint/build.gradle.kts @@ -8,8 +8,8 @@ dependencies { api(project(":jacodb-api")) api(project(":jacodb-taint-configuration")) - implementation(project(":jacodb-analysis:actors")) - implementation(project(":jacodb-analysis:ifds")) + api(project(":jacodb-analysis:actors")) + api(project(":jacodb-analysis:ifds")) implementation(Libs.kotlin_logging) implementation(Libs.slf4j_simple) diff --git a/jacodb-cli/build.gradle.kts b/jacodb-cli/build.gradle.kts index f675ff24b..9fec8db25 100644 --- a/jacodb-cli/build.gradle.kts +++ b/jacodb-cli/build.gradle.kts @@ -5,7 +5,6 @@ plugins { dependencies { api(project(":jacodb-core")) api(project(":jacodb-analysis:taint")) - api(project(":jacodb-analysis:ifds")) api(project(":jacodb-api")) implementation(Libs.kotlin_logging) diff --git a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt index 923ff591c..d7f3e5cd1 100644 --- a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt +++ b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt @@ -48,6 +48,7 @@ import org.jacodb.ifds.taint.collectTaintComputationData import org.jacodb.ifds.taint.runTaintAnalysis import org.jacodb.ifds.taint.taintIfdsSystem import org.jacodb.ifds.unused.collectUnusedResults +import org.jacodb.ifds.unused.runUnusedAnalysis import org.jacodb.ifds.unused.unusedIfdsSystem import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages @@ -98,7 +99,7 @@ suspend fun launchAnalysesByConfig( "Unused" -> { val system = unusedIfdsSystem("ifds", graph.classpath, graph, chunkStrategy = chunkStrategy) - system.runNpeAnalysis(methods, timeout = 60.seconds) + system.runUnusedAnalysis(methods, timeout = 60.seconds) system.collectUnusedResults().map { it.toSarif() } } From cb1ddbb492c926f260f54d7301c97f4b0f34094c Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 17:33:53 +0300 Subject: [PATCH 41/64] [ifds] wip: fix test --- .../analysis/graph/ApplicationGraphFactory.kt | 18 +-- .../org/jacodb/analysis/graph/JcNoopInst.kt | 33 ---- .../graph/SimplifiedJcApplicationGraph.kt | 149 ------------------ .../org/jacodb/ifds/taint/SystemExtensions.kt | 1 + .../analysis/impl/JavaAnalysisApiTest.java | 20 +-- 5 files changed, 6 insertions(+), 215 deletions(-) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt index e4dfdd9e7..973e66b50 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt @@ -26,29 +26,15 @@ import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.impl.features.usagesExt import java.util.concurrent.CompletableFuture -/** - * Creates an instance of [SimplifiedJcApplicationGraph], see its docs for more info. - */ -suspend fun JcClasspath.newApplicationGraphForAnalysis(bannedPackagePrefixes: List? = null): JcApplicationGraph { - val mainGraph = JcApplicationGraphImpl(this, usagesExt()) - return if (bannedPackagePrefixes != null) { - SimplifiedJcApplicationGraph(mainGraph, bannedPackagePrefixes) - } else { - SimplifiedJcApplicationGraph(mainGraph, defaultBannedPackagePrefixes) - } -} - /** * Async adapter for calling [newApplicationGraphForAnalysis] from Java. * * See also: [answer on StackOverflow](https://stackoverflow.com/a/52887677/3592218). */ @OptIn(DelicateCoroutinesApi::class) -fun JcClasspath.newApplicationGraphForAnalysisAsync( - bannedPackagePrefixes: List? = null, -): CompletableFuture = +fun JcClasspath.newApplicationGraphForAnalysisAsync(): CompletableFuture = GlobalScope.future { - newApplicationGraphForAnalysis(bannedPackagePrefixes) + JcApplicationGraphImpl(this@newApplicationGraphForAnalysisAsync, usagesExt()) } val defaultBannedPackagePrefixes: List = listOf( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt deleted file mode 100644 index 3d693800a..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/JcNoopInst.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.graph - -import org.jacodb.api.cfg.JcExpr -import org.jacodb.api.cfg.JcInst -import org.jacodb.api.cfg.JcInstLocation -import org.jacodb.api.cfg.JcInstVisitor - -data class JcNoopInst(override val location: JcInstLocation) : JcInst { - override val operands: List - get() = emptyList() - - override fun accept(visitor: JcInstVisitor): T { - return visitor.visitExternalJcInst(this) - } - - override fun toString(): String = "noop" -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt deleted file mode 100644 index efc65b24b..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/SimplifiedJcApplicationGraph.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.graph - -import kotlinx.coroutines.runBlocking -import org.jacodb.api.JcClassType -import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.api.cfg.JcInst -import org.jacodb.api.cfg.JcVirtualCallExpr -import org.jacodb.api.ext.cfg.callExpr -import org.jacodb.api.ext.isSubClassOf -import org.jacodb.impl.cfg.JcInstLocationImpl -import org.jacodb.impl.features.hierarchyExt - -/** - * This is adopted specially for IFDS [JcApplicationGraph] that - * 1. Ignores method calls matching [bannedPackagePrefixes] (i.e., treats them as simple instructions with no callees) - * 2. In [callers] returns only call sites that were visited before - * 3. Adds a special [JcNoopInst] instruction to the beginning of each method - * (because backward analysis may want for method to start with neutral instruction) - */ -internal class SimplifiedJcApplicationGraph( - private val graph: JcApplicationGraph, - private val bannedPackagePrefixes: List, -) : JcApplicationGraph by graph { - private val hierarchyExtension = runBlocking { - classpath.hierarchyExt() - } - - private val visitedCallers: MutableMap> = mutableMapOf() - - private val cache: MutableMap> = mutableMapOf() - - // For backward analysis we may want for method to start with "neutral" operation => - // we add noop to the beginning of every method - private fun getStartInst(method: JcMethod): JcNoopInst { - val lineNumber = method.flowGraph().entries.firstOrNull()?.lineNumber?.let { it - 1 } ?: -1 - return JcNoopInst(JcInstLocationImpl(method, -1, lineNumber)) - } - - override fun predecessors(node: JcInst): Sequence { - val method = methodOf(node) - return when (node) { - getStartInst(method) -> { - emptySequence() - } - - in graph.entryPoints(method) -> { - sequenceOf(getStartInst(method)) - } - - else -> { - graph.predecessors(node) - } - } - } - - override fun successors(node: JcInst): Sequence { - val method = methodOf(node) - return when (node) { - getStartInst(method) -> { - graph.entryPoints(method) - } - - else -> { - graph.successors(node) - } - } - } - - private fun getOverrides(method: JcMethod): List { - return if (cache.containsKey(method)) { - cache[method]!! - } else { - val res = hierarchyExtension.findOverrides(method).toList() - cache[method] = res - res - } - } - - private fun calleesUnmarked(node: JcInst): Sequence { - val callees = graph.callees(node).filterNot { callee -> - bannedPackagePrefixes.any { callee.enclosingClass.name.startsWith(it) } - } - - val callExpr = node.callExpr as? JcVirtualCallExpr ?: return callees - val instanceClass = (callExpr.instance.type as? JcClassType)?.jcClass ?: return callees - - return callees - .flatMap { callee -> - val allOverrides = getOverrides(callee) - .filter { - it.enclosingClass isSubClassOf instanceClass || - // TODO: use only down-most override here - instanceClass isSubClassOf it.enclosingClass - } - - // TODO: maybe filter inaccessible methods here? - allOverrides + sequenceOf(callee) - } - } - - override fun callees(node: JcInst): Sequence { - return calleesUnmarked(node).also { - it.forEach { method -> - visitedCallers.getOrPut(method) { mutableSetOf() }.add(node) - } - } - } - - /** - * This is IFDS-algorithm aware optimization. - * In IFDS we don't need all method callers, we need only method callers which we visited earlier. - */ - // TODO: Think if this optimization is really needed - override fun callers(method: JcMethod): Sequence = - visitedCallers[method].orEmpty().asSequence() - - override fun entryPoints(method: JcMethod): Sequence = try { - sequenceOf(getStartInst(method)) - } catch (e: Throwable) { - // we couldn't find instructions list - // TODO: maybe fix flowGraph() - emptySequence() - } - - override fun exitPoints(method: JcMethod): Sequence = try { - graph.exitPoints(method) - } catch (e: Throwable) { - // we couldn't find instructions list - // TODO: maybe fix flowGraph() - emptySequence() - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index 52ba86d32..680976626 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -84,6 +84,7 @@ suspend fun ActorSystem.runTaintAnalysis( } @OptIn(DelicateCoroutinesApi::class) +@JvmName("runTaintAnalysisAsync") fun ActorSystem.runTaintAnalysisAsync( methods: Collection, timeout: Duration = 60.seconds, diff --git a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java index 19a8487c4..2c017f224 100644 --- a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java +++ b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java @@ -16,7 +16,6 @@ package org.jacodb.analysis.impl; -import kotlin.Unit; import kotlin.time.DurationUnit; import org.jacodb.actors.api.ActorSystem; import org.jacodb.analysis.graph.ApplicationGraphFactory; @@ -36,9 +35,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import static kotlin.time.DurationKt.toDuration; @@ -63,7 +60,7 @@ public void testJavaAnalysisApi() throws ExecutionException, InterruptedExceptio List methodsToAnalyze = analyzedClass.getDeclaredMethods(); JcApplicationGraph applicationGraph = ApplicationGraphFactory - .newApplicationGraphForAnalysisAsync(classpath, null) + .newApplicationGraphForAnalysisAsync(classpath) .get(); ActorSystem system = taintIfdsSystem( @@ -72,21 +69,10 @@ public void testJavaAnalysisApi() throws ExecutionException, InterruptedExceptio applicationGraph, getDefaultBannedPackagePrefixes(), ChunkStrategiesKt.getClassChunkStrategy()); - CompletableFuture future = runTaintAnalysisAsync( + runTaintAnalysisAsync( system, methodsToAnalyze, - toDuration(30, DurationUnit.SECONDS)); - future.get(); - } - - @Test - public void testCustomBannedPackagesApi() throws ExecutionException, InterruptedException { - List bannedPackages = new ArrayList<>(ApplicationGraphFactory.getDefaultBannedPackagePrefixes()); - bannedPackages.add("my.package.that.wont.be.analyzed"); - - JcApplicationGraph customGraph = ApplicationGraphFactory - .newApplicationGraphForAnalysisAsync(classpath, bannedPackages) + toDuration(30, DurationUnit.SECONDS)) .get(); - Assertions.assertNotNull(customGraph); } } From 36c3cf89870340d4a096c084a8e33eef8e0ce9a6 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 14 May 2024 23:03:58 +0300 Subject: [PATCH 42/64] [ifds] wip: remove entities, simplify code --- .../org/jacodb/ifds/domain/FlowFunctions.kt | 36 ---- .../org/jacodb/ifds/domain/FlowScope.kt | 32 ---- .../org/jacodb/analysis/ifds/Analyzer.kt | 35 ---- .../kotlin/org/jacodb/ifds/DefaultAnalyzer.kt | 125 ------------ .../kotlin/org/jacodb/ifds/FunctionWrapper.kt | 91 --------- .../ifds/{ => common}/ChunkStrategies.kt | 3 +- .../ifds => ifds/common}/FlowFunctions.kt | 26 ++- .../ifds/{ => common}/IndirectionHandler.kt | 4 +- .../org/jacodb/ifds/common/JcBaseAnalyzer.kt | 181 ++++++++++++++++++ .../jacodb/ifds/{ => common}/JcIfdsContext.kt | 15 +- .../{analysis => ifds}/config/Condition.kt | 16 +- .../{analysis => ifds}/config/Position.kt | 18 +- .../{analysis => ifds}/config/TaintAction.kt | 12 +- .../ifds => ifds/domain}/AccessPath.kt | 2 +- .../ifds => ifds/domain}/Accessors.kt | 2 +- .../kotlin/org/jacodb/ifds/npe/Context.kt | 17 +- .../{analysis => ifds}/npe/NpeAnalyzers.kt | 49 +++-- .../npe/NpeFlowFunctions.kt | 44 ++--- .../kotlin/org/jacodb/ifds/npe/Results.kt | 4 +- .../org/jacodb/ifds/npe/SystemExtensions.kt | 5 +- .../jacodb/{analysis => ifds}/npe/Utils.kt | 8 +- .../org/jacodb/ifds/sarif/Vulnerability.kt | 4 +- .../kotlin/org/jacodb/ifds/taint/Context.kt | 33 +--- .../kotlin/org/jacodb/ifds/taint/Results.kt | 2 - .../org/jacodb/ifds/taint/SystemExtensions.kt | 4 +- .../taint/TaintAnalyzers.kt | 75 ++------ .../{analysis => ifds}/taint/TaintFacts.kt | 4 +- .../taint/TaintFlowFunctions.kt | 38 ++-- .../jacodb/{analysis => ifds}/taint/Types.kt | 2 +- .../kotlin/org/jacodb/ifds/unused/Context.kt | 18 +- .../kotlin/org/jacodb/ifds/unused/Results.kt | 1 - .../jacodb/ifds/unused/SystemExtensions.kt | 7 +- .../unused/UnusedVariableAnalyzer.kt | 22 ++- .../unused/UnusedVariableFacts.kt | 4 +- .../unused/UnusedVariableFlowFunctions.kt | 13 +- .../jacodb/{analysis => ifds}/unused/Utils.kt | 6 +- .../{analysis/ifds => ifds/util}/Maybe.kt | 2 +- .../jacodb/{analysis => ifds}/util/Utils.kt | 4 +- .../analysis/impl/JavaAnalysisApiTest.java | 2 +- .../analysis/impl/ConditionEvaluatorTest.kt | 13 +- .../org/jacodb/analysis/impl/IfdsNpeTest.kt | 3 - .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 6 +- .../jacodb/analysis/impl/IfdsUnusedTest.kt | 3 - .../analysis/impl/TaintFlowFunctionsTest.kt | 29 ++- .../src/main/kotlin/org/jacodb/cli/main.kt | 10 +- 45 files changed, 392 insertions(+), 638 deletions(-) delete mode 100644 jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunctions.kt delete mode 100644 jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/{ => common}/ChunkStrategies.kt (96%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis/ifds => ifds/common}/FlowFunctions.kt (83%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/{ => common}/IndirectionHandler.kt (97%) create mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/{ => common}/JcIfdsContext.kt (82%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/config/Condition.kt (95%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/config/Position.kt (90%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/config/TaintAction.kt (91%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis/ifds => ifds/domain}/AccessPath.kt (99%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis/ifds => ifds/domain}/Accessors.kt (96%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/npe/NpeAnalyzers.kt (74%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/npe/NpeFlowFunctions.kt (95%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/npe/Utils.kt (90%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/taint/TaintAnalyzers.kt (58%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/taint/TaintFacts.kt (92%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/taint/TaintFlowFunctions.kt (96%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/taint/Types.kt (96%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/unused/UnusedVariableAnalyzer.kt (72%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/unused/UnusedVariableFacts.kt (92%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/unused/UnusedVariableFlowFunctions.kt (92%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/unused/Utils.kt (93%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis/ifds => ifds/util}/Maybe.kt (98%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{analysis => ifds}/util/Utils.kt (95%) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunctions.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunctions.kt deleted file mode 100644 index fab06b82d..000000000 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowFunctions.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.domain - -interface FlowFunctions { - fun FlowScope.sequent( - next: Stmt, - ) - - fun FlowScope.callToReturn( - returnSite: Stmt, - ) - - fun FlowScope.callToStart( - calleeStart: Stmt, - ) - - fun FlowScope.exitToReturnSite( - callerEdge: Edge, - returnSite: Stmt, - ) -} diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt deleted file mode 100644 index cb0004934..000000000 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/FlowScope.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.domain - -import org.jacodb.ifds.messages.RunnerMessage - -class FlowScope( - val edge: Edge, - private val messages: MutableList, -) { - fun add(newMessage: RunnerMessage) { - messages.add(newMessage) - } - - fun addAll(newMessages: Collection) { - messages.addAll(newMessages) - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt deleted file mode 100644 index bbd198a78..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Analyzer.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.analysis.ifds - -import org.jacodb.api.JcMethod -import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Edge - -interface Analyzer { - val flowFunctions: FlowFunctions - - /** - * Method for obtaining initial domain facts at the method entrypoint. - * Commonly, it is only `listOf(Zero)`. - */ - fun obtainPossibleStartFacts(method: JcMethod): Collection - - fun handleNewEdge( - edge: Edge, - ): List -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt deleted file mode 100644 index a0e92bc3e..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/DefaultAnalyzer.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds - -import org.jacodb.ifds.domain.Analyzer -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.FlowFunctions -import org.jacodb.ifds.domain.FlowScope -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.messages.EdgeMessage -import org.jacodb.ifds.messages.NotificationOnStart -import org.jacodb.ifds.messages.ResolvedCall -import org.jacodb.ifds.messages.UnresolvedCall -import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.api.cfg.JcInst -import org.jacodb.api.ext.cfg.callExpr - -typealias JcFlowScope = FlowScope - -class DefaultAnalyzer( - private val applicationGraph: JcApplicationGraph, - private val flowFunctions: FlowFunctions, - private val runnerId: RunnerId, -) : Analyzer { - override fun handle(message: AnalyzerMessage): Collection = buildList { - when (message) { - is EdgeMessage -> { - val scope = JcFlowScope(message.edge, this) - scope.processEdge(message.edge) - } - - is ResolvedCall -> { - val scope = JcFlowScope(message.edge, this) - @Suppress("UNCHECKED_CAST") - scope.processResolvedCall(message as ResolvedCall) - } - - is NotificationOnStart -> { - val scope = JcFlowScope(message.summaryEdge, this) - scope.processNotificationOnStart(message) - } - - else -> { - error("Unexpected message: $message") - } - } - } - - private fun JcFlowScope.processEdge(edge: Edge) { - val toStmt = edge.to.statement - val method = applicationGraph.methodOf(toStmt) - - val callExpr = toStmt.callExpr - val isExit = toStmt in applicationGraph.exitPoints(method) - - when { - callExpr != null -> processCall(edge) - !isExit -> processSequent(edge) - } - } - - private fun JcFlowScope.processCall(edge: Edge) { - val callMessage = UnresolvedCall(runnerId, edge) - add(callMessage) - - val successors = applicationGraph.successors(edge.to.statement) - - flowFunctions.run { - for (successor in successors) { - callToReturn(successor) - } - } - } - - private fun JcFlowScope.processSequent(edge: Edge) { - val successors = applicationGraph.successors(edge.to.statement) - - flowFunctions.run { - for (successor in successors) { - sequent(successor) - } - } - } - - - private fun JcFlowScope.processResolvedCall( - resolvedCall: ResolvedCall, - ) { - val entryPoints = applicationGraph.entryPoints(resolvedCall.method) - - flowFunctions.run { - for (entryPoint in entryPoints) { - callToStart(entryPoint) - } - } - } - - - private fun JcFlowScope.processNotificationOnStart(message: NotificationOnStart) { - val successors = applicationGraph.successors(message.subscribingEdge.to.statement) - - flowFunctions.run { - for (successor in successors) { - exitToReturnSite(message.subscribingEdge, successor) - } - } - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt deleted file mode 100644 index 7852abd72..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/FunctionWrapper.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds - -import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.FlowFunctions -import org.jacodb.ifds.domain.FlowScope -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.SubscriptionOnStart - -typealias JcEventProcessor = FlowScope.(Event) -> Unit - -class JcFlowFunctionsAdapter( - private val runnerId: RunnerId, - private val jcAnalyzer: Analyzer, - private val jcEventProcessor: JcEventProcessor, -) : FlowFunctions { - private val jcFlowFunctions = jcAnalyzer.flowFunctions - - override fun FlowScope.sequent(next: JcInst) = - jcFlowFunctions - .sequent(edge.to.statement, next, edge.to.fact) - .forEach { newFact -> - val newEdge = Edge(edge.from, Vertex(next, newFact)) - processNewEdge(runnerId, newEdge, Reason.Sequent(edge)) - } - - override fun FlowScope.callToReturn(returnSite: JcInst) = - jcFlowFunctions - .callToReturn(edge.to.statement, returnSite, edge.to.fact) - .forEach { newFact -> - val newEdge = Edge(edge.from, Vertex(returnSite, newFact)) - processNewEdge(runnerId, newEdge, Reason.CallToReturn(edge)) - } - - override fun FlowScope.callToStart(calleeStart: JcInst) = - jcFlowFunctions - .callToStart(edge.to.statement, calleeStart, edge.to.fact) - .forEach { newFact -> - val vertex = Vertex(calleeStart, newFact) - - val subscription = SubscriptionOnStart(runnerId, vertex, runnerId, edge) - add(subscription) - - val newEdge = Edge(vertex, vertex) - processNewEdge(runnerId, newEdge, Reason.CallToStart(edge)) - } - - override fun FlowScope.exitToReturnSite( - callerEdge: Edge, - returnSite: JcInst, - ) = jcFlowFunctions - .exitToReturnSite(callerEdge.to.statement, returnSite, edge.to.statement, edge.to.fact) - .forEach { newFact -> - val newEdge = Edge(callerEdge.from, Vertex(returnSite, newFact)) - processNewEdge(runnerId, newEdge, Reason.ExitToReturnSite(callerEdge, edge)) - } - - private fun FlowScope.processNewEdge( - runnerId: RunnerId, - newEdge: Edge, - reason: Reason, - ) { - val edge = NewEdge(runnerId, newEdge, reason) - add(edge) - - val jcEvents = jcAnalyzer.handleNewEdge(newEdge) - for (event in jcEvents) { - jcEventProcessor(event) - } - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/ChunkStrategies.kt similarity index 96% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/ChunkStrategies.kt index f5826b247..57a3afc53 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/ChunkStrategies.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/ChunkStrategies.kt @@ -14,12 +14,13 @@ * limitations under the License. */ -package org.jacodb.ifds +package org.jacodb.ifds.common import org.jacodb.api.JcClassOrInterface import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.packageName +import org.jacodb.ifds.ChunkStrategy import org.jacodb.ifds.domain.Chunk data object SingletonChunk : Chunk diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/FlowFunctions.kt similarity index 83% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/FlowFunctions.kt index 6d2dddd3e..f1145b773 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/FlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/FlowFunctions.kt @@ -14,11 +14,9 @@ * limitations under the License. */ -package org.jacodb.analysis.ifds +package org.jacodb.ifds.common -import org.jacodb.api.cfg.JcInst - -interface FlowFunctions { +interface FlowFunctions { /** * Sequent flow function. * @@ -31,8 +29,8 @@ interface FlowFunctions { * ``` */ fun sequent( - current: JcInst, - next: JcInst, + current: Stmt, + next: Stmt, fact: Fact, ): Collection @@ -48,8 +46,8 @@ interface FlowFunctions { * ``` */ fun callToReturn( - callStatement: JcInst, - returnSite: JcInst, + callStatement: Stmt, + returnSite: Stmt, fact: Fact ): Collection @@ -61,7 +59,7 @@ interface FlowFunctions { * : \ * : \ (call-to-start edge) * : \ - * : [ START p ] + * : [ START p ] :: calleeStart * : | * : [ EXIT p ] * : / @@ -70,8 +68,8 @@ interface FlowFunctions { * ``` */ fun callToStart( - callStatement: JcInst, - calleeStart: JcInst, + callStatement: Stmt, + calleeStart: Stmt, fact: Fact, ): Collection @@ -92,9 +90,9 @@ interface FlowFunctions { * ``` */ fun exitToReturnSite( - callStatement: JcInst, - returnSite: JcInst, - exitStatement: JcInst, + callStatement: Stmt, + returnSite: Stmt, + exitStatement: Stmt, fact: Fact, ): Collection } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/IndirectionHandler.kt similarity index 97% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/IndirectionHandler.kt index e281e8382..d91597b22 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/IndirectionHandler.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/IndirectionHandler.kt @@ -14,12 +14,12 @@ * limitations under the License. */ -package org.jacodb.ifds +package org.jacodb.ifds.common import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef -import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.ifds.taint.TaintDomainFact import org.jacodb.api.JcClassType import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt new file mode 100644 index 000000000..f63319033 --- /dev/null +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt @@ -0,0 +1,181 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.common + +import org.jacodb.api.JcMethod +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst +import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.ifds.domain.Analyzer +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.AnalyzerMessage +import org.jacodb.ifds.messages.EdgeMessage +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.NotificationOnStart +import org.jacodb.ifds.messages.ResolvedCall +import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.ifds.messages.SubscriptionOnStart +import org.jacodb.ifds.messages.UnresolvedCall + +abstract class JcBaseAnalyzer( + protected val selfRunnerId: RunnerId, + protected val graph: JcApplicationGraph, +) : Analyzer { + abstract val flowFunctions: FlowFunctions + + override fun handle(message: AnalyzerMessage): Collection = buildList { + when (message) { + is EdgeMessage -> { + processEdge(message.edge) + } + + is ResolvedCall -> { + @Suppress("UNCHECKED_CAST") + processResolvedCall(message as ResolvedCall) + } + + is NotificationOnStart -> { + processNotificationOnStart(message) + } + + else -> { + error("Unexpected message: $message") + } + } + } + + private fun MutableList.processEdge(edge: Edge) { + val toStmt = edge.to.statement + val method = graph.methodOf(toStmt) + + val callExpr = toStmt.callExpr + val isExit = toStmt in graph.exitPoints(method) + + when { + callExpr != null -> processCall(edge) + !isExit -> processSequent(edge) + } + } + + private fun MutableList.processCall(edge: Edge) { + val callMessage = UnresolvedCall(selfRunnerId, edge) + add(callMessage) + + val reason = Reason.CallToReturn(edge) + + val successors = graph.successors(edge.to.statement) + + for (successor in successors) { + val facts = flowFunctions.callToReturn( + callStatement = edge.to.statement, + returnSite = successor, + edge.to.fact + ) + for (fact in facts) { + val newEdge = Edge(edge.from, Vertex(successor, fact)) + processNewEdge(selfRunnerId, newEdge, reason) + } + } + } + + private fun MutableList.processSequent(edge: Edge) { + val reason = Reason.Sequent(edge) + + val successors = graph.successors(edge.to.statement) + + for (successor in successors) { + val facts = flowFunctions.sequent(current = edge.to.statement, next = successor, edge.to.fact) + for (fact in facts) { + val newEdge = Edge(edge.from, Vertex(successor, fact)) + processNewEdge(selfRunnerId, newEdge, reason) + } + } + } + + + private fun MutableList.processResolvedCall( + resolvedCall: ResolvedCall, + ) { + val edge = resolvedCall.edge + val reason = Reason.CallToStart(edge) + + val entryPoints = graph.entryPoints(resolvedCall.method) + + for (entryPoint in entryPoints) { + val facts = flowFunctions.callToStart( + callStatement = edge.to.statement, + calleeStart = entryPoint, + edge.to.fact + ) + for (fact in facts) { + val vertex = Vertex(entryPoint, fact) + + val subscription = SubscriptionOnStart(selfRunnerId, vertex, selfRunnerId, edge) + add(subscription) + + val newEdge = Edge(vertex, vertex) + processNewEdge(selfRunnerId, newEdge, reason) + } + } + } + + + private fun MutableList.processNotificationOnStart( + message: NotificationOnStart + ) { + val callerEdge = message.subscribingEdge + val returnSites = graph.successors(callerEdge.to.statement) + + val edge = message.summaryEdge + val reason = Reason.ExitToReturnSite(callerEdge, edge) + + for (returnSite in returnSites) { + val facts = flowFunctions.exitToReturnSite( + callStatement = callerEdge.to.statement, + returnSite = returnSite, + exitStatement = edge.to.statement, + edge.to.fact + ) + for (fact in facts) { + val newEdge = Edge(callerEdge.from, Vertex(returnSite, fact)) + processNewEdge(selfRunnerId, newEdge, reason) + } + } + } + + private fun MutableList.processNewEdge( + runnerId: RunnerId, + newEdge: Edge, + reason: Reason, + ) { + val newEdgeMessage = NewEdge(runnerId, newEdge, reason) + add(newEdgeMessage) + + onNewEdge(newEdge) + } + + protected abstract fun MutableList.onNewEdge(newEdge: Edge) + + /** + * Method for obtaining initial domain facts at the method entrypoint. + * Commonly, it is only `listOf(Zero)`. + */ + abstract fun obtainPossibleStartFacts(method: JcMethod): Collection +} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt similarity index 82% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt index 87e83aeef..0605b8526 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt @@ -14,26 +14,25 @@ * limitations under the License. */ -package org.jacodb.ifds +package org.jacodb.ifds.common import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorFactory import org.jacodb.api.JcClasspath -import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.ChunkResolver +import org.jacodb.ifds.IfdsContext import org.jacodb.ifds.domain.Analyzer import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.domain.FlowFunctions import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.impl.features.HierarchyExtensionImpl class JcIfdsContext( private val cp: JcClasspath, - private val graph: JcApplicationGraph, private val bannedPackagePrefixes: List, private val chunkStrategy: ChunkResolver, - private val flowFunctionsFactory: (RunnerId) -> FlowFunctions, + private val analyzerFactory: (RunnerId) -> Analyzer, ) : IfdsContext { override fun chunkByMessage(message: RunnerMessage): Chunk = chunkStrategy.chunkByMessage(message) @@ -42,11 +41,7 @@ class JcIfdsContext( message.runnerId override fun getAnalyzer(chunk: Chunk, runnerId: RunnerId): Analyzer = - DefaultAnalyzer( - graph, - flowFunctionsFactory(runnerId), - runnerId - ) + analyzerFactory(runnerId) override fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId) = ActorFactory { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/Condition.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt similarity index 95% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/Condition.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt index 92a765463..7c794e759 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/Condition.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt @@ -14,14 +14,14 @@ * limitations under the License. */ -package org.jacodb.analysis.config - -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.onSome -import org.jacodb.analysis.ifds.toPath -import org.jacodb.analysis.taint.Tainted +package org.jacodb.ifds.config + +import org.jacodb.ifds.domain.AccessPath +import org.jacodb.ifds.domain.ElementAccessor +import org.jacodb.ifds.util.Maybe +import org.jacodb.ifds.util.onSome +import org.jacodb.ifds.domain.toPath +import org.jacodb.ifds.taint.Tainted import org.jacodb.api.cfg.JcBool import org.jacodb.api.cfg.JcConstant import org.jacodb.api.cfg.JcInt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/Position.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt similarity index 90% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/Position.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt index a6e238a36..4ca0b1cd2 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/Position.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt @@ -14,16 +14,16 @@ * limitations under the License. */ -package org.jacodb.analysis.config +package org.jacodb.ifds.config -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.fmap -import org.jacodb.analysis.ifds.toMaybe -import org.jacodb.analysis.ifds.toPathOrNull -import org.jacodb.analysis.util.getArgument -import org.jacodb.analysis.util.thisInstance +import org.jacodb.ifds.domain.AccessPath +import org.jacodb.ifds.domain.ElementAccessor +import org.jacodb.ifds.util.Maybe +import org.jacodb.ifds.util.fmap +import org.jacodb.ifds.util.toMaybe +import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.util.getArgument +import org.jacodb.ifds.util.thisInstance import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcAssignInst diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt similarity index 91% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt index 59403b099..15e6f3db6 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/config/TaintAction.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt @@ -14,13 +14,13 @@ * limitations under the License. */ -package org.jacodb.analysis.config +package org.jacodb.ifds.config -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.fmap -import org.jacodb.analysis.ifds.map -import org.jacodb.analysis.taint.Tainted +import org.jacodb.ifds.domain.AccessPath +import org.jacodb.ifds.util.Maybe +import org.jacodb.ifds.util.fmap +import org.jacodb.ifds.util.map +import org.jacodb.ifds.taint.Tainted import org.jacodb.taint.configuration.AssignMark import org.jacodb.taint.configuration.CopyAllMarks import org.jacodb.taint.configuration.CopyMark diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/AccessPath.kt similarity index 99% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/AccessPath.kt index 9210b0dd7..b50d6b2cd 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/AccessPath.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/AccessPath.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.ifds +package org.jacodb.ifds.domain import org.jacodb.api.JcField import org.jacodb.api.cfg.JcArrayAccess diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/Accessors.kt similarity index 96% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/Accessors.kt index 885582f36..8e8311455 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Accessors.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/Accessors.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.ifds +package org.jacodb.ifds.domain import org.jacodb.api.JcField diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt index 4469aee33..968456c47 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt @@ -16,17 +16,14 @@ package org.jacodb.ifds.npe -import org.jacodb.analysis.npe.NpeAnalyzer -import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkResolver import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver -import org.jacodb.ifds.JcFlowFunctionsAdapter -import org.jacodb.ifds.JcIfdsContext +import org.jacodb.ifds.common.ClassChunkStrategy +import org.jacodb.ifds.common.JcIfdsContext +import org.jacodb.ifds.taint.TaintDomainFact fun npeIfdsContext( cp: JcClasspath, @@ -36,7 +33,6 @@ fun npeIfdsContext( ): JcIfdsContext = JcIfdsContext( cp, - graph, bannedPackagePrefixes, DefaultChunkResolver(chunkStrategy) ) { runnerId -> @@ -45,10 +41,5 @@ fun npeIfdsContext( else -> error("Unexpected runnerId: $runnerId") } - JcFlowFunctionsAdapter( - runnerId, - analyzer - ) { event -> - add(event) - } + analyzer } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeAnalyzers.kt similarity index 74% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeAnalyzers.kt index 4992ff014..18f8591f7 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeAnalyzers.kt @@ -14,23 +14,21 @@ * limitations under the License. */ -package org.jacodb.analysis.npe - -import org.jacodb.analysis.config.CallPositionToJcValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.ifds.Analyzer -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintEdge -import org.jacodb.analysis.taint.Tainted +package org.jacodb.ifds.npe + import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.ifds.common.JcBaseAnalyzer +import org.jacodb.ifds.config.CallPositionToJcValueResolver +import org.jacodb.ifds.config.FactAwareConditionEvaluator +import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.NewFinding import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.npe.NpeVulnerability -import org.jacodb.ifds.taint.TaintVulnerability +import org.jacodb.ifds.taint.TaintDomainFact +import org.jacodb.ifds.taint.Tainted import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.taint.configuration.TaintMark import org.jacodb.taint.configuration.TaintMethodSink @@ -39,9 +37,12 @@ private val logger = mu.KotlinLogging.logger {} class NpeAnalyzer( - private val selfRunnerId: RunnerId, - private val graph: JcApplicationGraph, -) : Analyzer { + selfRunnerId: RunnerId, + graph: JcApplicationGraph, +) : JcBaseAnalyzer( + selfRunnerId, + graph +) { val cp = graph.classpath private val taintConfigurationFeature: TaintConfigurationFeature? by lazy { @@ -62,25 +63,23 @@ class NpeAnalyzer( return statement in graph.exitPoints(statement.location.method) } - override fun handleNewEdge( - edge: TaintEdge, - ): List = buildList { - if (isExitPoint(edge.to.statement)) { - add(org.jacodb.ifds.messages.NewSummaryEdge(selfRunnerId, edge)) + override fun MutableList.onNewEdge(newEdge: Edge) { + if (isExitPoint(newEdge.to.statement)) { + add(org.jacodb.ifds.messages.NewSummaryEdge(selfRunnerId, newEdge)) } - val fact = edge.to.fact + val fact = newEdge.to.fact if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { - if (fact.variable.isDereferencedAt(edge.to.statement)) { + if (fact.variable.isDereferencedAt(newEdge.to.statement)) { val message = "NPE" // TODO - val vulnerability = NpeVulnerability(message, sink = edge.to) + val vulnerability = NpeVulnerability(message, sink = newEdge.to) logger.info { "Found sink=${vulnerability.sink} in ${vulnerability.sink.statement.location.method}" } add(NewFinding(selfRunnerId, vulnerability)) } } run { - val callExpr = edge.to.statement.callExpr ?: return@run + val callExpr = newEdge.to.statement.callExpr ?: return@run val callee = callExpr.method.method val config = taintConfigurationFeature?.getConfigForMethod(callee) ?: return@run @@ -94,13 +93,13 @@ class NpeAnalyzer( // Determine whether 'edge.to' is a sink via config: val conditionEvaluator = FactAwareConditionEvaluator( fact, - CallPositionToJcValueResolver(edge.to.statement), + CallPositionToJcValueResolver(newEdge.to.statement), ) for (item in config.filterIsInstance()) { if (item.condition.accept(conditionEvaluator)) { - logger.trace { "Found sink at ${edge.to} in ${edge.from.statement.location.method} on $item" } + logger.trace { "Found sink at ${newEdge.to} in ${newEdge.from.statement.location.method} on $item" } val message = item.ruleNote - val vulnerability = NpeVulnerability(message, sink = edge.to, rule = item) + val vulnerability = NpeVulnerability(message, sink = newEdge.to, rule = item) add(NewFinding(selfRunnerId, vulnerability)) } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt similarity index 95% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt index aa2b3c28e..06e1947cb 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/NpeFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt @@ -14,27 +14,27 @@ * limitations under the License. */ -package org.jacodb.analysis.npe - -import org.jacodb.analysis.config.BasicConditionEvaluator -import org.jacodb.analysis.config.CallPositionToAccessPathResolver -import org.jacodb.analysis.config.CallPositionToJcValueResolver -import org.jacodb.analysis.config.EntryPointPositionToAccessPathResolver -import org.jacodb.analysis.config.EntryPointPositionToJcValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.config.TaintActionEvaluator -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.ifds.onSome -import org.jacodb.analysis.ifds.toPath -import org.jacodb.analysis.ifds.toPathOrNull -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.getArgumentsOf -import org.jacodb.analysis.util.startsWith -import org.jacodb.analysis.util.thisInstance +package org.jacodb.ifds.npe + +import org.jacodb.ifds.config.BasicConditionEvaluator +import org.jacodb.ifds.config.CallPositionToAccessPathResolver +import org.jacodb.ifds.config.CallPositionToJcValueResolver +import org.jacodb.ifds.config.EntryPointPositionToAccessPathResolver +import org.jacodb.ifds.config.EntryPointPositionToJcValueResolver +import org.jacodb.ifds.config.FactAwareConditionEvaluator +import org.jacodb.ifds.config.TaintActionEvaluator +import org.jacodb.ifds.domain.AccessPath +import org.jacodb.ifds.domain.ElementAccessor +import org.jacodb.ifds.common.FlowFunctions +import org.jacodb.ifds.util.onSome +import org.jacodb.ifds.domain.toPath +import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.taint.TaintDomainFact +import org.jacodb.ifds.taint.TaintZeroFact +import org.jacodb.ifds.taint.Tainted +import org.jacodb.ifds.util.getArgumentsOf +import org.jacodb.ifds.util.startsWith +import org.jacodb.ifds.util.thisInstance import org.jacodb.api.JcArrayType import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod @@ -75,7 +75,7 @@ class ForwardNpeFlowFunctions( private val cp: JcClasspath, private val graph: JcApplicationGraph, private val taintConfigurationFeature: TaintConfigurationFeature?, -) : FlowFunctions { +) : FlowFunctions { fun obtainPossibleStartFacts( method: JcMethod, ): Collection = buildSet { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt index b2a2edb7c..26a6a5ca0 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt @@ -16,8 +16,8 @@ package org.jacodb.ifds.npe -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintVertex +import org.jacodb.ifds.taint.TaintDomainFact +import org.jacodb.ifds.taint.TaintVertex import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.Finding diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt index 99e2704d2..797119477 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt @@ -23,14 +23,13 @@ import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.npe.NpeAnalyzer -import org.jacodb.analysis.taint.TaintDomainFact +import org.jacodb.ifds.taint.TaintDomainFact 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.ifds.ChunkStrategy -import org.jacodb.ifds.ClassChunkStrategy +import org.jacodb.ifds.common.ClassChunkStrategy import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt similarity index 90% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt index 3a0bbd27e..ac192b81c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/npe/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.jacodb.analysis.npe +package org.jacodb.ifds.npe -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.toPathOrNull -import org.jacodb.analysis.util.startsWith +import org.jacodb.ifds.domain.AccessPath +import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.util.startsWith import org.jacodb.api.cfg.JcExpr import org.jacodb.api.cfg.JcInst import org.jacodb.api.cfg.JcInstanceCallExpr diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt index 5ee0ac851..5e0f4f21d 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt @@ -17,8 +17,8 @@ package org.jacodb.ifds.sarif import io.github.detekt.sarif4k.Level -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.unused.UnusedVariableDomainFact +import org.jacodb.ifds.taint.TaintDomainFact +import org.jacodb.ifds.unused.UnusedVariableDomainFact import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.npe.NpeVulnerability import org.jacodb.ifds.result.EagerTraceGraph diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt index 510d5da74..d556b7d26 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt @@ -16,54 +16,29 @@ package org.jacodb.ifds.taint -import org.jacodb.analysis.taint.BackwardTaintAnalyzer -import org.jacodb.analysis.taint.ForwardTaintAnalyzer -import org.jacodb.analysis.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkResolver import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.ClassChunkStrategy +import org.jacodb.ifds.common.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver -import org.jacodb.ifds.JcFlowFunctionsAdapter -import org.jacodb.ifds.JcIfdsContext -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.common.JcIfdsContext -private fun complementRunner(type: RunnerId): RunnerId = - when (type) { - ForwardRunnerId -> BackwardRunnerId - BackwardRunnerId -> ForwardRunnerId - else -> error("unexpected runner: $type") - } fun taintIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List, chunkStrategy: ChunkStrategy = ClassChunkStrategy, - useBackwardRunner: Boolean = false, ): JcIfdsContext = JcIfdsContext( cp, - graph, bannedPackagePrefixes, DefaultChunkResolver(chunkStrategy) ) { runnerId -> - val analyzer = when (runnerId) { + when (runnerId) { is ForwardRunnerId -> ForwardTaintAnalyzer(ForwardRunnerId, graph) - is BackwardRunnerId -> BackwardTaintAnalyzer(BackwardRunnerId, ForwardRunnerId, graph) + is BackwardRunnerId -> TODO("Backward runner not implemented yet") else -> error("Unexpected runnerId: $runnerId") } - - JcFlowFunctionsAdapter( - runnerId, - analyzer - ) { event -> - if (useBackwardRunner || !(event is NewEdge<*, *> && event.reason is Reason.FromOtherRunner)) { - add(event) - } - } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt index 16349f633..480671069 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt @@ -16,8 +16,6 @@ package org.jacodb.ifds.taint -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintVertex import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.Finding diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt index 680976626..a8972555e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt @@ -26,14 +26,12 @@ import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.taint.ForwardTaintAnalyzer -import org.jacodb.analysis.taint.TaintDomainFact 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.ifds.ChunkStrategy -import org.jacodb.ifds.ClassChunkStrategy +import org.jacodb.ifds.common.ClassChunkStrategy import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzers.kt similarity index 58% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzers.kt index 7b57d5fc1..510d46af8 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzers.kt @@ -14,44 +14,40 @@ * limitations under the License. */ -package org.jacodb.analysis.taint +package org.jacodb.ifds.taint -import org.jacodb.analysis.config.CallPositionToJcValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.ifds.Analyzer import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.ifds.common.JcBaseAnalyzer +import org.jacodb.ifds.config.CallPositionToJcValueResolver +import org.jacodb.ifds.config.FactAwareConditionEvaluator import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.messages.NewFinding import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.taint.TaintVulnerability import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.taint.configuration.TaintMethodSink private val logger = mu.KotlinLogging.logger {} - class ForwardTaintAnalyzer( - private val selfRunnerId: RunnerId, - private val graph: JcApplicationGraph, -) : Analyzer { - private val cp = graph.classpath - + selfRunnerId: RunnerId, + graph: JcApplicationGraph, +) : JcBaseAnalyzer( + selfRunnerId, + graph, +) { private val taintConfigurationFeature: TaintConfigurationFeature? by lazy { - cp.features + graph.classpath.features ?.singleOrNull { it is TaintConfigurationFeature } ?.let { it as TaintConfigurationFeature } } - - override val flowFunctions: ForwardTaintFlowFunctions by lazy { - ForwardTaintFlowFunctions(cp, graph, taintConfigurationFeature) + override val flowFunctions by lazy { + ForwardTaintFlowFunctions(graph.classpath, graph, taintConfigurationFeature) } private fun isExitPoint(statement: JcInst): Boolean { @@ -62,22 +58,20 @@ class ForwardTaintAnalyzer( method: JcMethod, ): Collection = flowFunctions.obtainPossibleStartFacts(method) - override fun handleNewEdge( - edge: TaintEdge, - ): List = buildList { - if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(selfRunnerId, edge)) + override fun MutableList.onNewEdge(newEdge: Edge) { + if (isExitPoint(newEdge.to.statement)) { + add(NewSummaryEdge(selfRunnerId, newEdge)) } run { - val callExpr = edge.to.statement.callExpr ?: return@run + val callExpr = newEdge.to.statement.callExpr ?: return@run val callee = callExpr.method.method val config = taintConfigurationFeature?.getConfigForMethod(callee) ?: return@run // TODO: not always we want to skip sinks on Zero facts. // Some rules might have ConstantTrue or just true (when evaluated with Zero fact) condition. - val fact = edge.to.fact + val fact = newEdge.to.fact if (fact !is Tainted) { return@run } @@ -85,12 +79,12 @@ class ForwardTaintAnalyzer( // Determine whether 'edge.to' is a sink via config: val conditionEvaluator = FactAwareConditionEvaluator( fact, - CallPositionToJcValueResolver(edge.to.statement), + CallPositionToJcValueResolver(newEdge.to.statement), ) for (item in config.filterIsInstance()) { if (item.condition.accept(conditionEvaluator)) { val message = item.ruleNote - val vulnerability = TaintVulnerability(message, sink = edge.to, rule = item) + val vulnerability = TaintVulnerability(message, sink = newEdge.to, rule = item) logger.info { "Found sink=${vulnerability.sink} in ${vulnerability.sink.statement.location.method}" } add(NewFinding(selfRunnerId, vulnerability)) } @@ -99,32 +93,3 @@ class ForwardTaintAnalyzer( } } - -class BackwardTaintAnalyzer( - private val selfRunnerId: RunnerId, - private val otherRunnerId: RunnerId, - private val graph: JcApplicationGraph, -) : Analyzer { - - override val flowFunctions: BackwardTaintFlowFunctions by lazy { - BackwardTaintFlowFunctions(graph.classpath, graph) - } - - override fun obtainPossibleStartFacts( - method: JcMethod, - ): Collection { - return listOf(TaintZeroFact) - } - - private fun isExitPoint(statement: JcInst): Boolean { - return statement in graph.exitPoints(statement.location.method) - } - - override fun handleNewEdge( - edge: TaintEdge, - ): List = buildList { - if (isExitPoint(edge.to.statement)) { - add(NewEdge(otherRunnerId, Edge(edge.to, edge.to), Reason.FromOtherRunner(edge, selfRunnerId))) - } - } -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFacts.kt similarity index 92% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFacts.kt index 0fec8b62c..388088c6c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFacts.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFacts.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.jacodb.analysis.taint +package org.jacodb.ifds.taint -import org.jacodb.analysis.ifds.AccessPath +import org.jacodb.ifds.domain.AccessPath import org.jacodb.taint.configuration.TaintMark sealed interface TaintDomainFact diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt similarity index 96% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt index a6ef8f1a4..2baff72e3 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/TaintFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt @@ -14,23 +14,23 @@ * limitations under the License. */ -package org.jacodb.analysis.taint - -import org.jacodb.analysis.config.BasicConditionEvaluator -import org.jacodb.analysis.config.CallPositionToAccessPathResolver -import org.jacodb.analysis.config.CallPositionToJcValueResolver -import org.jacodb.analysis.config.EntryPointPositionToAccessPathResolver -import org.jacodb.analysis.config.EntryPointPositionToJcValueResolver -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.config.TaintActionEvaluator -import org.jacodb.analysis.ifds.ElementAccessor -import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.ifds.onSome -import org.jacodb.analysis.ifds.toPath -import org.jacodb.analysis.ifds.toPathOrNull -import org.jacodb.analysis.util.getArgumentsOf -import org.jacodb.analysis.util.startsWith -import org.jacodb.analysis.util.thisInstance +package org.jacodb.ifds.taint + +import org.jacodb.ifds.config.BasicConditionEvaluator +import org.jacodb.ifds.config.CallPositionToAccessPathResolver +import org.jacodb.ifds.config.CallPositionToJcValueResolver +import org.jacodb.ifds.config.EntryPointPositionToAccessPathResolver +import org.jacodb.ifds.config.EntryPointPositionToJcValueResolver +import org.jacodb.ifds.config.FactAwareConditionEvaluator +import org.jacodb.ifds.config.TaintActionEvaluator +import org.jacodb.ifds.domain.ElementAccessor +import org.jacodb.ifds.common.FlowFunctions +import org.jacodb.ifds.util.onSome +import org.jacodb.ifds.domain.toPath +import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.util.getArgumentsOf +import org.jacodb.ifds.util.startsWith +import org.jacodb.ifds.util.thisInstance import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph @@ -61,7 +61,7 @@ class ForwardTaintFlowFunctions( private val cp: JcClasspath, private val graph: JcApplicationGraph, private val taintConfigurationFeature: TaintConfigurationFeature?, -) : FlowFunctions { +) : FlowFunctions { fun obtainPossibleStartFacts( method: JcMethod, @@ -435,7 +435,7 @@ class ForwardTaintFlowFunctions( class BackwardTaintFlowFunctions( private val project: JcClasspath, private val graph: JcApplicationGraph, -) : FlowFunctions { +) : FlowFunctions { fun obtainPossibleStartFacts( method: JcMethod, ): Collection { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Types.kt similarity index 96% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Types.kt index 0614ec91f..63ebef0bc 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/taint/Types.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Types.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.taint +package org.jacodb.ifds.taint import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt index 1211884ea..5a70a81af 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt @@ -16,17 +16,13 @@ package org.jacodb.ifds.unused -import org.jacodb.analysis.unused.UnusedVariableAnalyzer -import org.jacodb.analysis.unused.UnusedVariableDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkResolver import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.ClassChunkStrategy import org.jacodb.ifds.DefaultChunkResolver -import org.jacodb.ifds.JcFlowFunctionsAdapter -import org.jacodb.ifds.JcIfdsContext +import org.jacodb.ifds.common.ClassChunkStrategy +import org.jacodb.ifds.common.JcIfdsContext fun unusedIfdsContext( cp: JcClasspath, @@ -36,19 +32,11 @@ fun unusedIfdsContext( ): JcIfdsContext = JcIfdsContext( cp, - graph, bannedPackagePrefixes, DefaultChunkResolver(chunkStrategy) ) { runnerId -> - val analyzer = when (runnerId) { + when (runnerId) { is SingletonRunnerId -> UnusedVariableAnalyzer(SingletonRunnerId, graph) else -> error("Unexpected runnerId: $runnerId") } - - JcFlowFunctionsAdapter( - runnerId, - analyzer - ) { event -> - add(event) - } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt index 21ce5a02d..8acb334ab 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt @@ -16,7 +16,6 @@ package org.jacodb.ifds.unused -import org.jacodb.analysis.unused.UnusedVariableDomainFact import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.Finding diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt index 2dfcbf496..644def91f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt @@ -23,17 +23,12 @@ import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.unused.UnusedVariable -import org.jacodb.analysis.unused.UnusedVariableAnalyzer -import org.jacodb.analysis.unused.UnusedVariableDomainFact -import org.jacodb.analysis.unused.UnusedVariableZeroFact -import org.jacodb.analysis.unused.isUsedAt 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.ifds.ChunkStrategy -import org.jacodb.ifds.ClassChunkStrategy +import org.jacodb.ifds.common.ClassChunkStrategy import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableAnalyzer.kt similarity index 72% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableAnalyzer.kt index 9279b8c88..16edb7e9d 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableAnalyzer.kt @@ -14,23 +14,25 @@ * limitations under the License. */ -package org.jacodb.analysis.unused +package org.jacodb.ifds.unused -import org.jacodb.analysis.ifds.Analyzer import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.common.JcBaseAnalyzer import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.NewSummaryEdge import org.jacodb.ifds.messages.RunnerMessage class UnusedVariableAnalyzer( - private val selfRunnerId: RunnerId, - private val graph: JcApplicationGraph, -) : Analyzer { - - override val flowFunctions: UnusedVariableFlowFunctions by lazy { + selfRunnerId: RunnerId, + graph: JcApplicationGraph, +) : JcBaseAnalyzer( + selfRunnerId, + graph, +) { + override val flowFunctions by lazy { UnusedVariableFlowFunctions(graph) } @@ -41,9 +43,9 @@ class UnusedVariableAnalyzer( return statement in graph.exitPoints(statement.location.method) } - override fun handleNewEdge(edge: Edge): List = buildList { - if (isExitPoint(edge.to.statement)) { - add(NewSummaryEdge(selfRunnerId, edge)) + override fun MutableList.onNewEdge(newEdge: Edge) { + if (isExitPoint(newEdge.to.statement)) { + add(NewSummaryEdge(selfRunnerId, newEdge)) } } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt similarity index 92% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt index 4def264ad..5e9c5fd4f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFacts.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.jacodb.analysis.unused +package org.jacodb.ifds.unused -import org.jacodb.analysis.ifds.AccessPath +import org.jacodb.ifds.domain.AccessPath import org.jacodb.api.cfg.JcInst sealed interface UnusedVariableDomainFact diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt similarity index 92% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt index e8a6a5f4a..f746dbf9b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/UnusedVariableFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt @@ -14,14 +14,13 @@ * limitations under the License. */ -package org.jacodb.analysis.unused +package org.jacodb.ifds.unused -import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.ifds.toPath -import org.jacodb.analysis.ifds.toPathOrNull -import org.jacodb.analysis.util.getArgumentsOf +import org.jacodb.ifds.common.FlowFunctions +import org.jacodb.ifds.domain.toPath +import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.util.getArgumentsOf import org.jacodb.api.JcClasspath -import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcInst @@ -31,7 +30,7 @@ import org.jacodb.api.ext.cfg.callExpr class UnusedVariableFlowFunctions( private val graph: JcApplicationGraph, -) : FlowFunctions { +) : FlowFunctions { private val cp: JcClasspath get() = graph.classpath diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt similarity index 93% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt index b21293831..ef56ff115 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/unused/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.jacodb.analysis.unused +package org.jacodb.ifds.unused -import org.jacodb.analysis.ifds.AccessPath -import org.jacodb.analysis.ifds.toPathOrNull +import org.jacodb.ifds.domain.AccessPath +import org.jacodb.ifds.domain.toPathOrNull import org.jacodb.api.cfg.JcArrayAccess import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcBranchingInst diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Maybe.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Maybe.kt similarity index 98% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Maybe.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Maybe.kt index be4356362..9505789f2 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/Maybe.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Maybe.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.ifds +package org.jacodb.ifds.util @JvmInline value class Maybe private constructor( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/util/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Utils.kt similarity index 95% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/util/Utils.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Utils.kt index 97f55df5c..b8d6208aa 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/util/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Utils.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.jacodb.analysis.util +package org.jacodb.ifds.util -import org.jacodb.analysis.ifds.AccessPath +import org.jacodb.ifds.domain.AccessPath import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.JcParameter diff --git a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java index 2c017f224..ea1e65873 100644 --- a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java +++ b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java @@ -24,7 +24,7 @@ import org.jacodb.api.JcDatabase; import org.jacodb.api.JcMethod; import org.jacodb.api.analysis.JcApplicationGraph; -import org.jacodb.ifds.ChunkStrategiesKt; +import org.jacodb.ifds.common.ChunkStrategiesKt; import org.jacodb.ifds.messages.CommonMessage; import org.jacodb.impl.JacoDB; import org.jacodb.impl.JcSettings; diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt index 0611e483b..767e00477 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt @@ -18,12 +18,12 @@ package org.jacodb.analysis.impl import io.mockk.every import io.mockk.mockk -import org.jacodb.analysis.config.BasicConditionEvaluator -import org.jacodb.analysis.config.FactAwareConditionEvaluator -import org.jacodb.analysis.ifds.Maybe -import org.jacodb.analysis.ifds.toMaybe -import org.jacodb.analysis.ifds.toPath -import org.jacodb.analysis.taint.Tainted +import org.jacodb.ifds.config.BasicConditionEvaluator +import org.jacodb.ifds.config.FactAwareConditionEvaluator +import org.jacodb.ifds.util.Maybe +import org.jacodb.ifds.util.toMaybe +import org.jacodb.ifds.domain.toPath +import org.jacodb.ifds.taint.Tainted import org.jacodb.api.JcClasspath import org.jacodb.api.JcPrimitiveType import org.jacodb.api.JcType @@ -37,7 +37,6 @@ import org.jacodb.api.cfg.JcValue import org.jacodb.taint.configuration.And import org.jacodb.taint.configuration.AnnotationType import org.jacodb.taint.configuration.Argument -import org.jacodb.taint.configuration.Condition import org.jacodb.taint.configuration.ConditionVisitor import org.jacodb.taint.configuration.ConstantBooleanValue import org.jacodb.taint.configuration.ConstantEq diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt index e6a273587..764a100a8 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt @@ -17,16 +17,13 @@ package org.jacodb.analysis.impl import kotlinx.coroutines.runBlocking -import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.api.JcMethod import org.jacodb.api.ext.constructors import org.jacodb.api.ext.findClass -import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.npe.NpeVulnerability import org.jacodb.ifds.npe.collectNpeResults -import org.jacodb.ifds.npe.npeIfdsContext import org.jacodb.ifds.npe.npeIfdsSystem import org.jacodb.ifds.npe.startNpeAnalysis import org.jacodb.impl.features.InMemoryHierarchy diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index f8a7a6aa3..1b1f3fc41 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -21,7 +21,7 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.taint.TaintZeroFact +import org.jacodb.ifds.taint.TaintZeroFact import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods @@ -108,12 +108,12 @@ class IfdsSqlTest : BaseAnalysisTest() { } @Test - fun `test bidirectional runner and other stuff`() = runBlocking { + fun `test trace collection`() = runBlocking { val className = "juliet.testcases.CWE89_SQL_Injection.s01.CWE89_SQL_Injection__Environment_executeBatch_51a" val clazz = cp.findClass(className) val badMethod = clazz.methods.single { it.name == "bad" } - val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes, useBackwardRunner = true) + val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) val system = system("ifds") { ProjectManager(ifdsContext) } system.startTaintAnalysis(badMethod) diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt index 82b323cb2..09619fc98 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt @@ -17,16 +17,13 @@ package org.jacodb.analysis.impl import kotlinx.coroutines.runBlocking -import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods -import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.unused.UnusedVulnerability import org.jacodb.ifds.unused.collectUnusedResults import org.jacodb.ifds.unused.startUnusedAnalysis -import org.jacodb.ifds.unused.unusedIfdsContext import org.jacodb.ifds.unused.unusedIfdsSystem import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt index 7192bbe3b..4e455276a 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt @@ -18,16 +18,14 @@ package org.jacodb.analysis.impl import io.mockk.every import io.mockk.mockk -import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.ifds.FlowFunctions -import org.jacodb.analysis.ifds.toPath -import org.jacodb.analysis.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.taint.TaintDomainFact -import org.jacodb.analysis.taint.TaintZeroFact -import org.jacodb.analysis.taint.Tainted -import org.jacodb.analysis.util.getArgument +import org.jacodb.ifds.common.FlowFunctions +import org.jacodb.ifds.domain.toPath +import org.jacodb.ifds.taint.ForwardTaintFlowFunctions +import org.jacodb.ifds.taint.TaintDomainFact +import org.jacodb.ifds.taint.TaintZeroFact +import org.jacodb.ifds.taint.Tainted +import org.jacodb.ifds.util.getArgument import org.jacodb.api.JcClassType -import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcArgument @@ -47,7 +45,6 @@ import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.taint.configuration.TaintMark import org.jacodb.testing.BaseTest import org.jacodb.testing.WithDB -import org.jacodb.testing.allClasspath import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test @@ -111,7 +108,7 @@ class TaintFlowFunctionsTest : BaseTest() { val x: JcLocal = JcLocalVar(1, "x", stringType) val y: JcLocal = JcLocalVar(2, "y", stringType) val inst = JcAssignInst(location = mockk(), lhv = x, rhv = y) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val facts = flowSpace.sequent(inst, next = mockk(), yTaint).toList() @@ -127,7 +124,7 @@ class TaintFlowFunctionsTest : BaseTest() { every { method } returns testMethod } }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("EXAMPLE")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), TaintZeroFact).toList() Assertions.assertEquals(listOf(TaintZeroFact, xTaint), facts) @@ -143,7 +140,7 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("REMOVE")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() Assertions.assertTrue(facts.isEmpty()) @@ -160,7 +157,7 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("COPY")) val yTaint = Tainted(y.toPath(), TaintMark("COPY")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() @@ -181,7 +178,7 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val arg0: JcArgument = cp.getArgument(testMethod.parameters[0])!! @@ -220,7 +217,7 @@ class TaintFlowFunctionsTest : BaseTest() { val exitStatement = JcReturnInst(location = mockk { every { method } returns testMethod }, returnValue = y) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val facts = flowSpace.exitToReturnSite(callStatement, returnSite = mockk(), exitStatement, yTaint).toList() diff --git a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt index d7f3e5cd1..c9b88c183 100644 --- a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt +++ b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt @@ -27,16 +27,16 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.encodeToStream import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.taint.TaintZeroFact +import org.jacodb.ifds.taint.TaintZeroFact import org.jacodb.api.JcClassOrInterface import org.jacodb.api.JcClassProcessingTask import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ClassChunkStrategy -import org.jacodb.ifds.MethodChunkStrategy -import org.jacodb.ifds.PackageChunkStrategy -import org.jacodb.ifds.SingletonChunkStrategy +import org.jacodb.ifds.common.ClassChunkStrategy +import org.jacodb.ifds.common.MethodChunkStrategy +import org.jacodb.ifds.common.PackageChunkStrategy +import org.jacodb.ifds.common.SingletonChunkStrategy import org.jacodb.ifds.npe.collectNpeComputationData import org.jacodb.ifds.npe.npeIfdsSystem import org.jacodb.ifds.npe.runNpeAnalysis From 69b8b88d41375c6498667c3e0baf1218fc49ea4c Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 15 May 2024 01:08:21 +0300 Subject: [PATCH 43/64] [ifds] wip: start analysis, unify extension functions, builders --- .../kotlin/org/jacodb/actors/api/Actor.kt | 6 +- .../org/jacodb/actors/api/signal/Signal.kt | 1 + .../impl/workers/InternalActorWorker.kt | 5 +- .../actors/impl/workers/UserActorWorker.kt | 13 +- .../kotlin/org/jacodb/ifds/ChunkResolver.kt | 96 ------------ .../org/jacodb/ifds/actors/ChunkManager.kt | 4 + .../jacodb/ifds/messages/AnalyzerMessages.kt | 5 + .../jacodb/ifds/common/JcAsyncIfdsFacade.kt | 63 ++++++++ .../org/jacodb/ifds/common/JcBaseAnalyzer.kt | 37 ++++- .../org/jacodb/ifds/common/JcChunkResolver.kt | 131 +++++++++++++++++ .../org/jacodb/ifds/common/JcIfdsContext.kt | 2 +- .../org/jacodb/ifds/common/JcIfdsFacade.kt | 87 +++++++++++ ...tionHandler.kt => JcIndirectionHandler.kt} | 2 +- .../org/jacodb/ifds/config/Condition.kt | 6 +- .../kotlin/org/jacodb/ifds/config/Position.kt | 6 +- .../org/jacodb/ifds/config/TaintAction.kt | 2 +- .../kotlin/org/jacodb/ifds/npe/Builders.kt | 92 ++++++++++++ .../kotlin/org/jacodb/ifds/npe/Context.kt | 45 ------ .../ifds/npe/{Results.kt => Findings.kt} | 0 .../org/jacodb/ifds/npe/NpeFlowFunctions.kt | 8 +- .../org/jacodb/ifds/npe/SystemExtensions.kt | 106 -------------- .../main/kotlin/org/jacodb/ifds/npe/Utils.kt | 4 +- .../kotlin/org/jacodb/ifds/taint/Builders.kt | 90 ++++++++++++ .../kotlin/org/jacodb/ifds/taint/Context.kt | 44 ------ .../ifds/taint/{Results.kt => Findings.kt} | 0 .../org/jacodb/ifds/taint/SystemExtensions.kt | 137 ------------------ .../org/jacodb/ifds/taint/TaintFacts.kt | 2 +- .../jacodb/ifds/taint/TaintFlowFunctions.kt | 6 +- .../kotlin/org/jacodb/ifds/unused/Builders.kt | 89 ++++++++++++ .../kotlin/org/jacodb/ifds/unused/Context.kt | 42 ------ .../ifds/unused/{Results.kt => Findings.kt} | 0 .../jacodb/ifds/unused/SystemExtensions.kt | 132 ----------------- .../jacodb/ifds/unused/UnusedVariableFacts.kt | 2 +- .../unused/UnusedVariableFlowFunctions.kt | 4 +- .../kotlin/org/jacodb/ifds/unused/Utils.kt | 4 +- .../ifds/{domain => util}/AccessPath.kt | 2 +- .../jacodb/ifds/{domain => util}/Accessors.kt | 2 +- .../ifds/util/{Utils.kt => Extensions.kt} | 1 - .../analysis/impl/JavaAnalysisApiTest.java | 13 +- .../analysis/impl/ConditionEvaluatorTest.kt | 2 +- .../org/jacodb/analysis/impl/IfdsNpeTest.kt | 13 +- .../org/jacodb/analysis/impl/IfdsSqlTest.kt | 36 ++--- .../jacodb/analysis/impl/IfdsUnusedTest.kt | 12 +- .../analysis/impl/JodaDateTimeAnalysisTest.kt | 30 ++-- .../analysis/impl/TaintFlowFunctionsTest.kt | 2 +- .../src/main/kotlin/org/jacodb/cli/main.kt | 39 +++-- 46 files changed, 694 insertions(+), 731 deletions(-) create mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt create mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt create mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/{IndirectionHandler.kt => JcIndirectionHandler.kt} (99%) create mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/{Results.kt => Findings.kt} (100%) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt create mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/{Results.kt => Findings.kt} (100%) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt create mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/{Results.kt => Findings.kt} (100%) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/{domain => util}/AccessPath.kt (99%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/{domain => util}/Accessors.kt (97%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/{Utils.kt => Extensions.kt} (97%) diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt index 18a94f4a7..b720833c7 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/Actor.kt @@ -20,5 +20,9 @@ import org.jacodb.actors.api.signal.Signal interface Actor { suspend fun receive(message: M) - suspend fun receive(signal: Signal) {} + suspend fun receive(signal: Signal) { + if (signal is Signal.Exception) { + signal.exception.printStackTrace() + } + } } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt index bfabb169a..ce2eeddc7 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt @@ -21,5 +21,6 @@ import org.jacodb.actors.api.ActorRef sealed interface Signal { data object Start : Signal data object PostStop : Signal + data class Exception(val exception: java.lang.Exception) : Signal class Terminated(val ref: ActorRef<*>) } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt index 286997203..0feb78a59 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt @@ -30,10 +30,7 @@ internal class InternalActorWorker( private val scope: CoroutineScope, ) : ActorWorker(path) { - override fun launchLoop( - coroutineContext: CoroutineContext, - actor: Actor, - ) { + override fun launchLoop(coroutineContext: CoroutineContext, actor: Actor) { scope.launch(coroutineContext) { loop(actor) } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt index 5b23cb767..15f7ae4a5 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt @@ -21,6 +21,7 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.onClosed import kotlinx.coroutines.channels.onSuccess import kotlinx.coroutines.launch +import mu.KLogger import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef @@ -43,10 +44,7 @@ internal class UserActorWorker( private var status = ActorStatus.BUSY private val working = AtomicBoolean(true) - override fun launchLoop( - coroutineContext: CoroutineContext, - actor: Actor, - ) { + override fun launchLoop(coroutineContext: CoroutineContext, actor: Actor) { scope.launch { sendInternal(watcher, WatcherMessage.Register(path)) actor.receive(Signal.Start) @@ -95,7 +93,12 @@ internal class UserActorWorker( ) { updateReceived() if (working.get()) { - actor.receive(message) + try { + actor.receive(message) + } catch (e: Exception) { + actor.receive(Signal.Exception(e)) + working.set(false) + } } } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt index ec04fed41..05febd822 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt @@ -17,21 +17,7 @@ package org.jacodb.ifds import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.EdgeMessage -import org.jacodb.ifds.messages.IndirectionMessage -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.NewFinding -import org.jacodb.ifds.messages.NewSummaryEdge -import org.jacodb.ifds.messages.NotificationOnEnd -import org.jacodb.ifds.messages.NotificationOnStart -import org.jacodb.ifds.messages.CollectData -import org.jacodb.ifds.messages.ResolvedCall import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.messages.StorageMessage -import org.jacodb.ifds.messages.SubscriptionOnEnd -import org.jacodb.ifds.messages.SubscriptionOnStart -import org.jacodb.ifds.messages.UnresolvedCall fun interface ChunkResolver { fun chunkByMessage(message: RunnerMessage): Chunk @@ -41,85 +27,3 @@ fun interface ChunkStrategy { fun chunkByStmt(stmt: Stmt): Chunk } -class DefaultChunkResolver( - private val chunkStrategy: ChunkStrategy, -) : ChunkResolver { - @Suppress("UNCHECKED_CAST") - override fun chunkByMessage(message: RunnerMessage): Chunk = - when (message) { - is AnalyzerMessage<*, *> -> { - when (message) { - is EdgeMessage<*, *> -> { - message as EdgeMessage - chunkStrategy.chunkByStmt(message.edge.to.statement) - } - - is NotificationOnEnd<*, *> -> { - message as NotificationOnEnd - chunkStrategy.chunkByStmt(message.summaryEdge.to.statement) - } - - is NotificationOnStart<*, *> -> { - message as NotificationOnStart - chunkStrategy.chunkByStmt(message.summaryEdge.to.statement) - } - - is ResolvedCall<*, *, *> -> { - message as ResolvedCall - chunkStrategy.chunkByStmt(message.edge.to.statement) - } - - else -> { - error("Unexpected message: $message") - } - } - } - - is IndirectionMessage -> { - when (message) { - is UnresolvedCall<*, *> -> { - message as UnresolvedCall - chunkStrategy.chunkByStmt(message.edge.to.statement) - } - - else -> { - error("Unexpected message: $message") - } - } - } - - is StorageMessage -> { - when (message) { - is NewEdge<*, *> -> { - message as NewEdge - chunkStrategy.chunkByStmt(message.edge.to.statement) - } - - is NewFinding<*, *> -> { - message as NewFinding - chunkStrategy.chunkByStmt(message.finding.vertex.statement) - } - - is NewSummaryEdge<*, *> -> { - message as NewSummaryEdge - chunkStrategy.chunkByStmt(message.edge.to.statement) - } - - is CollectData<*, *, *> -> { - message as CollectData - message.chunk - } - - is SubscriptionOnEnd<*, *> -> { - message as SubscriptionOnEnd - chunkStrategy.chunkByStmt(message.endVertex.statement) - } - - is SubscriptionOnStart<*, *> -> { - message as SubscriptionOnStart - chunkStrategy.chunkByStmt(message.startVertex.statement) - } - } - } - } -} diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt index bfd8f4d51..a115e13de 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt @@ -63,6 +63,10 @@ class ChunkManager( // TODO: explain why we do nothing here // do nothing } + + is Signal.Exception -> { + logger.error { signal.exception.stackTraceToString() } + } } } } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt index 694b86cb3..ba8ac92d0 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt @@ -21,6 +21,11 @@ import org.jacodb.ifds.domain.RunnerId interface AnalyzerMessage : RunnerMessage +data class StartAnalysis( + override val runnerId: RunnerId, + val method: Method, +) : AnalyzerMessage + data class EdgeMessage( override val runnerId: RunnerId, val edge: Edge, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt new file mode 100644 index 000000000..1487c16ea --- /dev/null +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.common + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.future.future +import org.jacodb.actors.api.ActorSystem +import org.jacodb.api.JcMethod +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.result.Finding +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +class JcAsyncIfdsFacade>( + system: ActorSystem, + startingRunnerId: RunnerId, +) { + private val scope = CoroutineScope(Job()) + private val ifdsFacade = JcIfdsFacade(system, startingRunnerId) + + @JvmName("runAnalysis") + fun runAnalysis( + methods: Collection, + timeout: Duration = 60.seconds, + ) = scope.future { + ifdsFacade.runAnalysis(methods, timeout) + } + + fun startAnalysis( + method: JcMethod, + ) = scope.future { + ifdsFacade.startAnalysis(method) + } + + fun awaitAnalysis() = scope.future { + ifdsFacade.awaitAnalysis() + } + + fun collectFindings() = scope.future { + ifdsFacade.collectFindings() + } + + fun collectComputationData() = scope.future { + ifdsFacade.collectComputationData() + } +} \ No newline at end of file diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt index f63319033..83b309664 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt @@ -31,6 +31,7 @@ import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.messages.NotificationOnStart import org.jacodb.ifds.messages.ResolvedCall import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.ifds.messages.StartAnalysis import org.jacodb.ifds.messages.SubscriptionOnStart import org.jacodb.ifds.messages.UnresolvedCall @@ -42,17 +43,27 @@ abstract class JcBaseAnalyzer( override fun handle(message: AnalyzerMessage): Collection = buildList { when (message) { + is StartAnalysis<*> -> { + @Suppress("UNCHECKED_CAST") + message as StartAnalysis + processStartAnalysis(message.method) + } + is EdgeMessage -> { processEdge(message.edge) } is ResolvedCall -> { @Suppress("UNCHECKED_CAST") - processResolvedCall(message as ResolvedCall) + message as ResolvedCall + processResolvedCall( + message.edge, + message.method + ) } is NotificationOnStart -> { - processNotificationOnStart(message) + processNotificationOnStart(message.subscribingEdge, message.summaryEdge) } else -> { @@ -61,6 +72,17 @@ abstract class JcBaseAnalyzer( } } + private fun MutableList.processStartAnalysis(method: JcMethod) { + for (fact in obtainPossibleStartFacts(method)) { + for (entryPoint in graph.entryPoints(method)) { + val vertex = Vertex(entryPoint, fact) + val edge = Edge(vertex, vertex) + val newEdgeMessage = NewEdge(selfRunnerId, edge, Reason.Initial) + add(newEdgeMessage) + } + } + } + private fun MutableList.processEdge(edge: Edge) { val toStmt = edge.to.statement val method = graph.methodOf(toStmt) @@ -111,12 +133,12 @@ abstract class JcBaseAnalyzer( private fun MutableList.processResolvedCall( - resolvedCall: ResolvedCall, + edge: Edge, + method: JcMethod, ) { - val edge = resolvedCall.edge val reason = Reason.CallToStart(edge) - val entryPoints = graph.entryPoints(resolvedCall.method) + val entryPoints = graph.entryPoints(method) for (entryPoint in entryPoints) { val facts = flowFunctions.callToStart( @@ -138,12 +160,11 @@ abstract class JcBaseAnalyzer( private fun MutableList.processNotificationOnStart( - message: NotificationOnStart + callerEdge: Edge, + edge: Edge ) { - val callerEdge = message.subscribingEdge val returnSites = graph.successors(callerEdge.to.statement) - val edge = message.summaryEdge val reason = Reason.ExitToReturnSite(callerEdge, edge) for (returnSite in returnSites) { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt new file mode 100644 index 000000000..941634603 --- /dev/null +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.common + +import org.jacodb.api.JcMethod +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.ChunkResolver +import org.jacodb.ifds.ChunkStrategy +import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.messages.AnalyzerMessage +import org.jacodb.ifds.messages.CollectData +import org.jacodb.ifds.messages.EdgeMessage +import org.jacodb.ifds.messages.IndirectionMessage +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.NewFinding +import org.jacodb.ifds.messages.NewSummaryEdge +import org.jacodb.ifds.messages.NotificationOnEnd +import org.jacodb.ifds.messages.NotificationOnStart +import org.jacodb.ifds.messages.ResolvedCall +import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.ifds.messages.StartAnalysis +import org.jacodb.ifds.messages.StorageMessage +import org.jacodb.ifds.messages.SubscriptionOnEnd +import org.jacodb.ifds.messages.SubscriptionOnStart +import org.jacodb.ifds.messages.UnresolvedCall + +class JcChunkResolver( + private val graph: JcApplicationGraph, + private val chunkStrategy: ChunkStrategy, +) : ChunkResolver { + @Suppress("UNCHECKED_CAST") + override fun chunkByMessage(message: RunnerMessage): Chunk = + when (message) { + is AnalyzerMessage<*, *> -> { + when (message) { + is EdgeMessage<*, *> -> { + message as EdgeMessage + chunkStrategy.chunkByStmt(message.edge.to.statement) + } + + is NotificationOnEnd<*, *> -> { + message as NotificationOnEnd + chunkStrategy.chunkByStmt(message.summaryEdge.to.statement) + } + + is NotificationOnStart<*, *> -> { + message as NotificationOnStart + chunkStrategy.chunkByStmt(message.summaryEdge.to.statement) + } + + is ResolvedCall<*, *, *> -> { + message as ResolvedCall + chunkStrategy.chunkByStmt(message.edge.to.statement) + } + + is StartAnalysis<*> -> { + message as StartAnalysis + + val stmt = graph.entryPoints(message.method).first() + chunkStrategy.chunkByStmt(stmt) + } + + else -> { + error("Unexpected message: $message") + } + } + } + + is IndirectionMessage -> { + when (message) { + is UnresolvedCall<*, *> -> { + message as UnresolvedCall + chunkStrategy.chunkByStmt(message.edge.to.statement) + } + + else -> { + error("Unexpected message: $message") + } + } + } + + is StorageMessage -> { + when (message) { + is NewEdge<*, *> -> { + message as NewEdge + chunkStrategy.chunkByStmt(message.edge.to.statement) + } + + is NewFinding<*, *> -> { + message as NewFinding + chunkStrategy.chunkByStmt(message.finding.vertex.statement) + } + + is NewSummaryEdge<*, *> -> { + message as NewSummaryEdge + chunkStrategy.chunkByStmt(message.edge.to.statement) + } + + is CollectData<*, *, *> -> { + message as CollectData + message.chunk + } + + is SubscriptionOnEnd<*, *> -> { + message as SubscriptionOnEnd + chunkStrategy.chunkByStmt(message.endVertex.statement) + } + + is SubscriptionOnStart<*, *> -> { + message as SubscriptionOnStart + chunkStrategy.chunkByStmt(message.startVertex.statement) + } + } + } + } +} \ No newline at end of file diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt index 0605b8526..1c5e5d210 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt @@ -45,6 +45,6 @@ class JcIfdsContext( override fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId) = ActorFactory { - IndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, parent, runnerId) + JcIndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, parent, runnerId) } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt new file mode 100644 index 000000000..115df9064 --- /dev/null +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.common + +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.jacodb.actors.api.ActorSystem +import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.api.JcMethod +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.domain.Edge +import org.jacodb.ifds.domain.Reason +import org.jacodb.ifds.domain.RunnerId +import org.jacodb.ifds.domain.Vertex +import org.jacodb.ifds.messages.CollectAllData +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.messages.NewEdge +import org.jacodb.ifds.messages.StartAnalysis +import org.jacodb.ifds.npe.NpeAnalyzer +import org.jacodb.ifds.npe.SingletonRunnerId +import org.jacodb.ifds.result.Finding +import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.ifds.result.mergeIfdsResults +import org.jacodb.ifds.taint.ForwardRunnerId +import org.jacodb.impl.features.usagesExt +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +class JcIfdsFacade>( + private val system: ActorSystem, + private val startingRunnerId: RunnerId, +) { + suspend fun runAnalysis( + methods: Collection, + timeout: Duration = 60.seconds, + ) = coroutineScope { + for (method in methods) { + startAnalysis(method) + } + val stopper = launch { + delay(timeout) + system.logger.info { "Timeout! Stopping the system..." } + system.stop() + } + system.awaitCompletion() + stopper.cancel() + system.resume() + } + + suspend fun startAnalysis( + method: JcMethod, + ) { + val message = StartAnalysis(startingRunnerId, method) + system.send(message) + } + + suspend fun awaitAnalysis() { + system.awaitCompletion() + } + + suspend fun collectFindings(): Collection = + collectComputationData().findings + + suspend fun collectComputationData(): IfdsComputationData { + val results = system.ask { CollectAllData(SingletonRunnerId, it) } + + @Suppress("UNCHECKED_CAST") + val ifdsData = results.values as Collection> + + return mergeIfdsResults(ifdsData) + } +} \ No newline at end of file diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/IndirectionHandler.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt similarity index 99% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/IndirectionHandler.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt index d91597b22..7b37af304 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/IndirectionHandler.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt @@ -34,7 +34,7 @@ import org.jacodb.ifds.messages.ResolvedCall import org.jacodb.ifds.messages.UnresolvedCall context(ActorContext) -class IndirectionHandler( +class JcIndirectionHandler( private val hierarchy: HierarchyExtension, private val bannedPackagePrefixes: List, private val parent: ActorRef, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt index 7c794e759..a50a66ea8 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt @@ -16,11 +16,11 @@ package org.jacodb.ifds.config -import org.jacodb.ifds.domain.AccessPath -import org.jacodb.ifds.domain.ElementAccessor +import org.jacodb.ifds.util.AccessPath +import org.jacodb.ifds.util.ElementAccessor import org.jacodb.ifds.util.Maybe import org.jacodb.ifds.util.onSome -import org.jacodb.ifds.domain.toPath +import org.jacodb.ifds.util.toPath import org.jacodb.ifds.taint.Tainted import org.jacodb.api.cfg.JcBool import org.jacodb.api.cfg.JcConstant diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt index 4ca0b1cd2..be79483cc 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt @@ -16,12 +16,12 @@ package org.jacodb.ifds.config -import org.jacodb.ifds.domain.AccessPath -import org.jacodb.ifds.domain.ElementAccessor +import org.jacodb.ifds.util.AccessPath +import org.jacodb.ifds.util.ElementAccessor import org.jacodb.ifds.util.Maybe import org.jacodb.ifds.util.fmap import org.jacodb.ifds.util.toMaybe -import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.util.toPathOrNull import org.jacodb.ifds.util.getArgument import org.jacodb.ifds.util.thisInstance import org.jacodb.api.JcClasspath diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt index 15e6f3db6..89b96c826 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt @@ -16,7 +16,7 @@ package org.jacodb.ifds.config -import org.jacodb.ifds.domain.AccessPath +import org.jacodb.ifds.util.AccessPath import org.jacodb.ifds.util.Maybe import org.jacodb.ifds.util.fmap import org.jacodb.ifds.util.map diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt new file mode 100644 index 000000000..59169bf4f --- /dev/null +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.npe + +import org.jacodb.actors.api.ActorSystem +import org.jacodb.actors.impl.system +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.api.JcClasspath +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.ChunkStrategy +import org.jacodb.ifds.common.JcChunkResolver +import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.common.ClassChunkStrategy +import org.jacodb.ifds.common.JcAsyncIfdsFacade +import org.jacodb.ifds.common.JcIfdsContext +import org.jacodb.ifds.common.JcIfdsFacade +import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.taint.TaintDomainFact + +fun npeIfdsContext( + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): JcIfdsContext = + JcIfdsContext( + cp, + bannedPackagePrefixes, + JcChunkResolver(graph, chunkStrategy) + ) { runnerId -> + val analyzer = when (runnerId) { + is SingletonRunnerId -> NpeAnalyzer(runnerId, graph) + else -> error("Unexpected runnerId: $runnerId") + } + + analyzer + } + +fun npeIfdsSystem( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): ActorSystem { + val context = npeIfdsContext( + cp, + graph, + bannedPackagePrefixes, + chunkStrategy + ) + return system(name) { + ProjectManager(context) + } +} + +fun npeIfdsFacade( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): JcIfdsFacade { + val system = npeIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + return JcIfdsFacade(system, SingletonRunnerId) +} + +fun asyncNpeIfdsFacade( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): JcAsyncIfdsFacade { + val system = npeIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + return JcAsyncIfdsFacade(system, SingletonRunnerId) +} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt deleted file mode 100644 index 968456c47..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Context.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.npe - -import org.jacodb.api.JcClasspath -import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.DefaultChunkResolver -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.common.JcIfdsContext -import org.jacodb.ifds.taint.TaintDomainFact - -fun npeIfdsContext( - cp: JcClasspath, - graph: JcApplicationGraph, - bannedPackagePrefixes: List, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, -): JcIfdsContext = - JcIfdsContext( - cp, - bannedPackagePrefixes, - DefaultChunkResolver(chunkStrategy) - ) { runnerId -> - val analyzer = when (runnerId) { - is SingletonRunnerId -> NpeAnalyzer(runnerId, graph) - else -> error("Unexpected runnerId: $runnerId") - } - - analyzer - } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt similarity index 100% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Results.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt index 06e1947cb..69e9e1251 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt @@ -23,12 +23,12 @@ import org.jacodb.ifds.config.EntryPointPositionToAccessPathResolver import org.jacodb.ifds.config.EntryPointPositionToJcValueResolver import org.jacodb.ifds.config.FactAwareConditionEvaluator import org.jacodb.ifds.config.TaintActionEvaluator -import org.jacodb.ifds.domain.AccessPath -import org.jacodb.ifds.domain.ElementAccessor +import org.jacodb.ifds.util.AccessPath +import org.jacodb.ifds.util.ElementAccessor import org.jacodb.ifds.common.FlowFunctions import org.jacodb.ifds.util.onSome -import org.jacodb.ifds.domain.toPath -import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.util.toPath +import org.jacodb.ifds.util.toPathOrNull import org.jacodb.ifds.taint.TaintDomainFact import org.jacodb.ifds.taint.TaintZeroFact import org.jacodb.ifds.taint.Tainted diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt deleted file mode 100644 index 797119477..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/SystemExtensions.kt +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.npe - -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import org.jacodb.actors.api.ActorSystem -import org.jacodb.actors.impl.system -import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.ifds.taint.TaintDomainFact -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.ifds.ChunkStrategy -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.actors.ProjectManager -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.CollectAllData -import org.jacodb.ifds.messages.CommonMessage -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.result.IfdsComputationData -import org.jacodb.ifds.result.mergeIfdsResults -import org.jacodb.impl.features.usagesExt -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds - -fun npeIfdsSystem( - name: String, - cp: JcClasspath, - graph: JcApplicationGraph, - bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, -): ActorSystem { - val context = npeIfdsContext( - cp, - graph, - bannedPackagePrefixes, - chunkStrategy - ) - return system(name) { - ProjectManager(context) - } -} - -suspend fun ActorSystem.runNpeAnalysis( - methods: Collection, - timeout: Duration = 60.seconds, -): Unit = coroutineScope { - for (method in methods) { - startNpeAnalysis(method) - } - val stopper = launch { - delay(timeout) - logger.info { "Timeout! Stopping the system..." } - stop() - } - awaitCompletion() - stopper.cancel() - resume() -} - -suspend fun ActorSystem.startNpeAnalysis(method: JcMethod) { - val cp = method.enclosingClass.classpath - val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val npeAnalyzer = NpeAnalyzer(SingletonRunnerId, graph) - for (fact in npeAnalyzer.obtainPossibleStartFacts(method)) { - for (entryPoint in graph.entryPoints(method)) { - val vertex = Vertex(entryPoint, fact) - val message = NewEdge(SingletonRunnerId, Edge(vertex, vertex), Reason.Initial) - send(message) - } - } -} - -suspend fun ActorSystem.collectNpeResults(): Collection = - collectNpeComputationData() - .findings - - -suspend fun ActorSystem.collectNpeComputationData(): IfdsComputationData { - val results = ask { CollectAllData(SingletonRunnerId, it) } - - @Suppress("UNCHECKED_CAST") - val ifdsData = results.values as Collection> - - return mergeIfdsResults(ifdsData) -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt index ac192b81c..513267c56 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt @@ -16,8 +16,8 @@ package org.jacodb.ifds.npe -import org.jacodb.ifds.domain.AccessPath -import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.util.AccessPath +import org.jacodb.ifds.util.toPathOrNull import org.jacodb.ifds.util.startsWith import org.jacodb.api.cfg.JcExpr import org.jacodb.api.cfg.JcInst diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt new file mode 100644 index 000000000..20964bd1e --- /dev/null +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.taint + +import org.jacodb.actors.api.ActorSystem +import org.jacodb.actors.impl.system +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.api.JcClasspath +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.ChunkStrategy +import org.jacodb.ifds.common.ClassChunkStrategy +import org.jacodb.ifds.common.JcChunkResolver +import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.common.JcAsyncIfdsFacade +import org.jacodb.ifds.common.JcIfdsContext +import org.jacodb.ifds.common.JcIfdsFacade +import org.jacodb.ifds.messages.CommonMessage + +fun taintIfdsContext( + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): JcIfdsContext = + JcIfdsContext( + cp, + bannedPackagePrefixes, + JcChunkResolver(graph, chunkStrategy) + ) { runnerId -> + when (runnerId) { + is ForwardRunnerId -> ForwardTaintAnalyzer(ForwardRunnerId, graph) + is BackwardRunnerId -> TODO("Backward runner is not implemented yet") + else -> error("Unexpected runnerId: $runnerId") + } + } + +fun taintIfdsSystem( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): ActorSystem { + val context = taintIfdsContext( + cp, + graph, + bannedPackagePrefixes, + chunkStrategy + ) + return system(name) { + ProjectManager(context) + } +} + +fun taintIfdsFacade( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): JcIfdsFacade { + val system = taintIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + return JcIfdsFacade(system, ForwardRunnerId) +} + +fun asyncTaintIfdsFacade( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): JcAsyncIfdsFacade { + val system = taintIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + return JcAsyncIfdsFacade(system, ForwardRunnerId) +} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt deleted file mode 100644 index d556b7d26..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Context.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.taint - -import org.jacodb.api.JcClasspath -import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.DefaultChunkResolver -import org.jacodb.ifds.common.JcIfdsContext - - -fun taintIfdsContext( - cp: JcClasspath, - graph: JcApplicationGraph, - bannedPackagePrefixes: List, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, -): JcIfdsContext = - JcIfdsContext( - cp, - bannedPackagePrefixes, - DefaultChunkResolver(chunkStrategy) - ) { runnerId -> - when (runnerId) { - is ForwardRunnerId -> ForwardTaintAnalyzer(ForwardRunnerId, graph) - is BackwardRunnerId -> TODO("Backward runner not implemented yet") - else -> error("Unexpected runnerId: $runnerId") - } - } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Findings.kt similarity index 100% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Results.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Findings.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt deleted file mode 100644 index a8972555e..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/SystemExtensions.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.taint - -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.future.future -import kotlinx.coroutines.launch -import org.jacodb.actors.api.ActorSystem -import org.jacodb.actors.impl.system -import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -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.ifds.ChunkStrategy -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.actors.ProjectManager -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.CollectAllData -import org.jacodb.ifds.messages.CommonMessage -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.result.IfdsComputationData -import org.jacodb.ifds.result.mergeIfdsResults -import org.jacodb.impl.features.usagesExt -import java.util.concurrent.CompletableFuture -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds - -fun taintIfdsSystem( - name: String, - cp: JcClasspath, - graph: JcApplicationGraph, - bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, -): ActorSystem { - val context = taintIfdsContext( - cp, - graph, - bannedPackagePrefixes, - chunkStrategy - ) - return system(name) { - ProjectManager(context) - } -} - -suspend fun ActorSystem.runTaintAnalysis( - methods: Collection, - timeout: Duration = 60.seconds, -): Unit = coroutineScope { - for (method in methods) { - startTaintAnalysis(method) - } - val stopper = launch { - delay(timeout) - logger.info { "Timeout! Stopping the system..." } - stop() - } - awaitCompletion() - stopper.cancel() - resume() -} - -@OptIn(DelicateCoroutinesApi::class) -@JvmName("runTaintAnalysisAsync") -fun ActorSystem.runTaintAnalysisAsync( - methods: Collection, - timeout: Duration = 60.seconds, -): CompletableFuture = GlobalScope.future { - runTaintAnalysis(methods, timeout) -} - -suspend fun ActorSystem.startTaintAnalysis(method: JcMethod) { - val cp = method.enclosingClass.classpath - val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val forwardTaintAnalyzer = ForwardTaintAnalyzer(ForwardRunnerId, graph) - - for (fact in forwardTaintAnalyzer.obtainPossibleStartFacts(method)) { - for (entryPoint in graph.entryPoints(method)) { - val vertex = Vertex(entryPoint, fact) - val message = NewEdge(ForwardRunnerId, Edge(vertex, vertex), Reason.Initial) - send(message) - } - } -} - -@OptIn(DelicateCoroutinesApi::class) -fun ActorSystem.startTaintAnalysisAsync( - method: JcMethod, -): CompletableFuture = GlobalScope.future { - startTaintAnalysis(method) -} - -suspend fun ActorSystem.collectTaintResults(): Collection = - collectTaintComputationData() - .findings - -@OptIn(DelicateCoroutinesApi::class) -fun ActorSystem.collectTaintResultsAsync(): CompletableFuture> = - GlobalScope.future { - collectTaintResults() - } - -suspend fun ActorSystem.collectTaintComputationData(): IfdsComputationData { - val results = ask { CollectAllData(ForwardRunnerId, it) } - - @Suppress("UNCHECKED_CAST") - val ifdsData = results.values as Collection> - - return mergeIfdsResults(ifdsData) -} - -@OptIn(DelicateCoroutinesApi::class) -fun ActorSystem.collectTaintComputationDataAsync(): CompletableFuture> = - GlobalScope.future { - collectTaintComputationData() - } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFacts.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFacts.kt index 388088c6c..16b22de89 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFacts.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFacts.kt @@ -16,7 +16,7 @@ package org.jacodb.ifds.taint -import org.jacodb.ifds.domain.AccessPath +import org.jacodb.ifds.util.AccessPath import org.jacodb.taint.configuration.TaintMark sealed interface TaintDomainFact diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt index 2baff72e3..4a5c2e538 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt @@ -23,11 +23,11 @@ import org.jacodb.ifds.config.EntryPointPositionToAccessPathResolver import org.jacodb.ifds.config.EntryPointPositionToJcValueResolver import org.jacodb.ifds.config.FactAwareConditionEvaluator import org.jacodb.ifds.config.TaintActionEvaluator -import org.jacodb.ifds.domain.ElementAccessor +import org.jacodb.ifds.util.ElementAccessor import org.jacodb.ifds.common.FlowFunctions import org.jacodb.ifds.util.onSome -import org.jacodb.ifds.domain.toPath -import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.util.toPath +import org.jacodb.ifds.util.toPathOrNull import org.jacodb.ifds.util.getArgumentsOf import org.jacodb.ifds.util.startsWith import org.jacodb.ifds.util.thisInstance diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt new file mode 100644 index 000000000..64404fc88 --- /dev/null +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.unused + +import org.jacodb.actors.api.ActorSystem +import org.jacodb.actors.impl.system +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.api.JcClasspath +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.ChunkStrategy +import org.jacodb.ifds.common.JcChunkResolver +import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.common.ClassChunkStrategy +import org.jacodb.ifds.common.JcAsyncIfdsFacade +import org.jacodb.ifds.common.JcIfdsContext +import org.jacodb.ifds.common.JcIfdsFacade +import org.jacodb.ifds.messages.CommonMessage + +fun unusedIfdsContext( + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): JcIfdsContext = + JcIfdsContext( + cp, + bannedPackagePrefixes, + JcChunkResolver(graph, chunkStrategy) + ) { runnerId -> + when (runnerId) { + is SingletonRunnerId -> UnusedVariableAnalyzer(SingletonRunnerId, graph) + else -> error("Unexpected runnerId: $runnerId") + } + } + +fun unusedIfdsSystem( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): ActorSystem { + val context = unusedIfdsContext( + cp, + graph, + bannedPackagePrefixes, + chunkStrategy + ) + return system(name) { + ProjectManager(context) + } +} + +fun unusedIfdsFacade( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): JcIfdsFacade { + val system = unusedIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + return JcIfdsFacade(system, SingletonRunnerId) +} + +fun asyncUnusedIfdsFacade( + name: String, + cp: JcClasspath, + graph: JcApplicationGraph, + bannedPackagePrefixes: List = defaultBannedPackagePrefixes, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, +): JcAsyncIfdsFacade { + val system = unusedIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + return JcAsyncIfdsFacade(system, SingletonRunnerId) +} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt deleted file mode 100644 index 5a70a81af..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Context.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.unused - -import org.jacodb.api.JcClasspath -import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.DefaultChunkResolver -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.common.JcIfdsContext - -fun unusedIfdsContext( - cp: JcClasspath, - graph: JcApplicationGraph, - bannedPackagePrefixes: List, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, -): JcIfdsContext = - JcIfdsContext( - cp, - bannedPackagePrefixes, - DefaultChunkResolver(chunkStrategy) - ) { runnerId -> - when (runnerId) { - is SingletonRunnerId -> UnusedVariableAnalyzer(SingletonRunnerId, graph) - else -> error("Unexpected runnerId: $runnerId") - } - } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Findings.kt similarity index 100% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Results.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Findings.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt deleted file mode 100644 index 644def91f..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/SystemExtensions.kt +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.unused - -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import org.jacodb.actors.api.ActorSystem -import org.jacodb.actors.impl.system -import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -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.ifds.ChunkStrategy -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.actors.ProjectManager -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.CollectAllData -import org.jacodb.ifds.messages.CommonMessage -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.result.IfdsComputationData -import org.jacodb.ifds.result.mergeIfdsResults -import org.jacodb.impl.features.usagesExt -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds - -fun unusedIfdsSystem( - name: String, - cp: JcClasspath, - graph: JcApplicationGraph, - bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, -): ActorSystem { - val context = unusedIfdsContext( - cp, - graph, - bannedPackagePrefixes, - chunkStrategy - ) - return system(name) { - ProjectManager(context) - } -} - -suspend fun ActorSystem.runUnusedAnalysis( - methods: Collection, - timeout: Duration = 60.seconds, -): Unit = coroutineScope { - for (method in methods) { - startUnusedAnalysis(method) - } - val stopper = launch { - delay(timeout) - logger.info { "Timeout! Stopping the system..." } - stop() - } - awaitCompletion() - stopper.cancel() - resume() -} - -suspend fun ActorSystem.startUnusedAnalysis(method: JcMethod) { - val cp = method.enclosingClass.classpath - val graph = JcApplicationGraphImpl(cp, cp.usagesExt()) - val unusedAnalyzer = UnusedVariableAnalyzer(SingletonRunnerId, graph) - - for (fact in unusedAnalyzer.obtainPossibleStartFacts(method)) { - for (entryPoint in graph.entryPoints(method)) { - val vertex = Vertex(entryPoint, fact) - val message = NewEdge(SingletonRunnerId, Edge(vertex, vertex), Reason.Initial) - send(message) - } - } -} - -suspend fun ActorSystem.collectUnusedResults(): Collection { - val data = collectUnusedComputationData() - - val allFacts = data.factsByStmt - - val used = hashMapOf() - for ((inst, facts) in allFacts) { - for (fact in facts) { - if (fact is UnusedVariable) { - used.putIfAbsent(fact.initStatement, false) - if (fact.variable.isUsedAt(inst)) { - used[fact.initStatement] = true - } - } - - } - } - val vulnerabilities = used.filterValues { !it }.keys.map { - UnusedVulnerability( - message = "Assigned value is unused", - sink = Vertex(it, UnusedVariableZeroFact) - ) - } - return vulnerabilities -} - -suspend fun ActorSystem.collectUnusedComputationData(): IfdsComputationData { - val results = ask { - CollectAllData( - SingletonRunnerId, - it - ) - } - - @Suppress("UNCHECKED_CAST") - val mergedData = - mergeIfdsResults(results.values as Collection>) - return mergedData -} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt index 5e9c5fd4f..abaecfb72 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt @@ -16,7 +16,7 @@ package org.jacodb.ifds.unused -import org.jacodb.ifds.domain.AccessPath +import org.jacodb.ifds.util.AccessPath import org.jacodb.api.cfg.JcInst sealed interface UnusedVariableDomainFact diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt index f746dbf9b..62f183960 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt @@ -17,8 +17,8 @@ package org.jacodb.ifds.unused import org.jacodb.ifds.common.FlowFunctions -import org.jacodb.ifds.domain.toPath -import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.util.toPath +import org.jacodb.ifds.util.toPathOrNull import org.jacodb.ifds.util.getArgumentsOf import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt index ef56ff115..ee4dca5bf 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt @@ -16,8 +16,8 @@ package org.jacodb.ifds.unused -import org.jacodb.ifds.domain.AccessPath -import org.jacodb.ifds.domain.toPathOrNull +import org.jacodb.ifds.util.AccessPath +import org.jacodb.ifds.util.toPathOrNull import org.jacodb.api.cfg.JcArrayAccess import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcBranchingInst diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/AccessPath.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/AccessPath.kt similarity index 99% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/AccessPath.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/AccessPath.kt index b50d6b2cd..c184151c5 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/AccessPath.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/AccessPath.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.domain +package org.jacodb.ifds.util import org.jacodb.api.JcField import org.jacodb.api.cfg.JcArrayAccess diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/Accessors.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Accessors.kt similarity index 97% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/Accessors.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Accessors.kt index 8e8311455..443a916ee 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/domain/Accessors.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Accessors.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.domain +package org.jacodb.ifds.util import org.jacodb.api.JcField diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Extensions.kt similarity index 97% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Utils.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Extensions.kt index b8d6208aa..d18ca073a 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Extensions.kt @@ -16,7 +16,6 @@ package org.jacodb.ifds.util -import org.jacodb.ifds.domain.AccessPath import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.JcParameter diff --git a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java index ea1e65873..be0eeb0a3 100644 --- a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java +++ b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java @@ -17,7 +17,6 @@ package org.jacodb.analysis.impl; import kotlin.time.DurationUnit; -import org.jacodb.actors.api.ActorSystem; import org.jacodb.analysis.graph.ApplicationGraphFactory; import org.jacodb.api.JcClassOrInterface; import org.jacodb.api.JcClasspath; @@ -25,7 +24,9 @@ import org.jacodb.api.JcMethod; import org.jacodb.api.analysis.JcApplicationGraph; import org.jacodb.ifds.common.ChunkStrategiesKt; -import org.jacodb.ifds.messages.CommonMessage; +import org.jacodb.ifds.common.JcAsyncIfdsFacade; +import org.jacodb.ifds.taint.TaintDomainFact; +import org.jacodb.ifds.taint.TaintVulnerability; import org.jacodb.impl.JacoDB; import org.jacodb.impl.JcSettings; import org.jacodb.impl.features.InMemoryHierarchy; @@ -40,8 +41,7 @@ import static kotlin.time.DurationKt.toDuration; import static org.jacodb.analysis.graph.ApplicationGraphFactory.getDefaultBannedPackagePrefixes; -import static org.jacodb.ifds.taint.SystemExtensionsKt.runTaintAnalysisAsync; -import static org.jacodb.ifds.taint.SystemExtensionsKt.taintIfdsSystem; +import static org.jacodb.ifds.taint.BuildersKt.asyncTaintIfdsFacade; public class JavaAnalysisApiTest { @@ -63,14 +63,13 @@ public void testJavaAnalysisApi() throws ExecutionException, InterruptedExceptio .newApplicationGraphForAnalysisAsync(classpath) .get(); - ActorSystem system = taintIfdsSystem( + JcAsyncIfdsFacade ifds = asyncTaintIfdsFacade( "ifds", applicationGraph.getClasspath(), applicationGraph, getDefaultBannedPackagePrefixes(), ChunkStrategiesKt.getClassChunkStrategy()); - runTaintAnalysisAsync( - system, + ifds.runAnalysis( methodsToAnalyze, toDuration(30, DurationUnit.SECONDS)) .get(); diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt index 767e00477..4fc978cd8 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt @@ -22,7 +22,7 @@ import org.jacodb.ifds.config.BasicConditionEvaluator import org.jacodb.ifds.config.FactAwareConditionEvaluator import org.jacodb.ifds.util.Maybe import org.jacodb.ifds.util.toMaybe -import org.jacodb.ifds.domain.toPath +import org.jacodb.ifds.util.toPath import org.jacodb.ifds.taint.Tainted import org.jacodb.api.JcClasspath import org.jacodb.api.JcPrimitiveType diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt index 764a100a8..99e8d0c35 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt @@ -18,14 +18,11 @@ package org.jacodb.analysis.impl import kotlinx.coroutines.runBlocking import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.api.JcMethod import org.jacodb.api.ext.constructors import org.jacodb.api.ext.findClass import org.jacodb.ifds.npe.NpeVulnerability -import org.jacodb.ifds.npe.collectNpeResults -import org.jacodb.ifds.npe.npeIfdsSystem -import org.jacodb.ifds.npe.startNpeAnalysis +import org.jacodb.ifds.npe.npeIfdsFacade import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.impl.features.usagesExt @@ -197,11 +194,11 @@ class IfdsNpeTest : BaseAnalysisTest() { } private fun findSinks(method: JcMethod): Collection = runBlocking { - val system = npeIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) + val ifds = npeIfdsFacade("ifds", cp, graph) - system.startNpeAnalysis(method) - system.awaitCompletion() - system.collectNpeResults() + ifds.startAnalysis(method) + ifds.awaitAnalysis() + ifds.collectFindings() } @ParameterizedTest diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt index 1b1f3fc41..62d808fa8 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt @@ -19,22 +19,16 @@ package org.jacodb.analysis.impl import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.ifds.taint.TaintZeroFact import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods -import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.result.buildTraceGraph import org.jacodb.ifds.sarif.sarifReportFromVulnerabilities import org.jacodb.ifds.sarif.toSarif import org.jacodb.ifds.taint.TaintVulnerability -import org.jacodb.ifds.taint.collectTaintComputationData -import org.jacodb.ifds.taint.collectTaintResults -import org.jacodb.ifds.taint.startTaintAnalysis -import org.jacodb.ifds.taint.taintIfdsContext -import org.jacodb.ifds.taint.taintIfdsSystem +import org.jacodb.ifds.taint.TaintZeroFact +import org.jacodb.ifds.taint.taintIfdsFacade import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.testing.WithDB @@ -69,12 +63,11 @@ class IfdsSqlTest : BaseAnalysisTest() { val methodName = "bad" val method = cp.findClass().declaredMethods.single { it.name == methodName } - val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = system("ifds") { ProjectManager(ifdsContext) } + val ifds = taintIfdsFacade("ifds", cp, graph) - system.startTaintAnalysis(method) - system.awaitCompletion() - val data = system.collectTaintComputationData() + ifds.startAnalysis(method) + ifds.awaitAnalysis() + val data = ifds.collectComputationData() val sinks = data.findings assertTrue(sinks.isNotEmpty()) val sink = sinks.first() @@ -84,11 +77,11 @@ class IfdsSqlTest : BaseAnalysisTest() { } private fun findSinks(method: JcMethod): Collection = runBlocking { - val system = taintIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) + val system = taintIfdsFacade("ifds", cp, graph) - system.startTaintAnalysis(method) - system.awaitCompletion() - system.collectTaintResults() + system.startAnalysis(method) + system.awaitAnalysis() + system.collectFindings() } @ParameterizedTest @@ -113,13 +106,12 @@ class IfdsSqlTest : BaseAnalysisTest() { val clazz = cp.findClass(className) val badMethod = clazz.methods.single { it.name == "bad" } - val ifdsContext = taintIfdsContext(cp, graph, defaultBannedPackagePrefixes) - val system = system("ifds") { ProjectManager(ifdsContext) } + val ifds = taintIfdsFacade("ifds", cp, graph, defaultBannedPackagePrefixes) - system.startTaintAnalysis(badMethod) - system.awaitCompletion() + ifds.startAnalysis(badMethod) + ifds.awaitAnalysis() - val data = system.collectTaintComputationData() + val data = ifds.collectComputationData() val sinks = data.findings assertTrue(sinks.isNotEmpty()) val sink = sinks.first() diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt index 09619fc98..a668c276a 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt @@ -22,9 +22,7 @@ import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods import org.jacodb.ifds.unused.UnusedVulnerability -import org.jacodb.ifds.unused.collectUnusedResults -import org.jacodb.ifds.unused.startUnusedAnalysis -import org.jacodb.ifds.unused.unusedIfdsSystem +import org.jacodb.ifds.unused.unusedIfdsFacade import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.testing.WithDB @@ -60,11 +58,11 @@ class IfdsUnusedTest : BaseAnalysisTest() { } private fun findSinks(method: JcMethod): Collection = runBlocking { - val system = unusedIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) + val system = unusedIfdsFacade("ifds", cp, graph, defaultBannedPackagePrefixes) - system.startUnusedAnalysis(method) - system.awaitCompletion() - system.collectUnusedResults() + system.startAnalysis(method) + system.awaitAnalysis() + system.collectFindings() } @ParameterizedTest diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt index 089069353..1b7296c0b 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt @@ -22,15 +22,9 @@ import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.ext.findClass -import org.jacodb.ifds.npe.collectNpeResults -import org.jacodb.ifds.npe.npeIfdsSystem -import org.jacodb.ifds.npe.runNpeAnalysis -import org.jacodb.ifds.taint.collectTaintResults -import org.jacodb.ifds.taint.runTaintAnalysis -import org.jacodb.ifds.taint.taintIfdsSystem -import org.jacodb.ifds.unused.collectUnusedResults -import org.jacodb.ifds.unused.runUnusedAnalysis -import org.jacodb.ifds.unused.unusedIfdsSystem +import org.jacodb.ifds.npe.npeIfdsFacade +import org.jacodb.ifds.taint.taintIfdsFacade +import org.jacodb.ifds.unused.unusedIfdsFacade import org.jacodb.impl.features.usagesExt import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.testing.BaseTest @@ -66,31 +60,31 @@ class JodaDateTimeAnalysisTest : BaseTest() { @Test fun `test taint analysis`() = runBlocking { - val system = taintIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) + val ifds = taintIfdsFacade("ifds", cp, graph, defaultBannedPackagePrefixes) val clazz = cp.findClass() val methods = clazz.declaredMethods - system.runTaintAnalysis(methods, timeout = 20.seconds) - val sinks = system.collectTaintResults() + ifds.runAnalysis(methods, timeout = 20.seconds) + val sinks = ifds.collectFindings() logger.info { "Vulnerabilities found: ${sinks.size}" } } @Test fun `test NPE analysis`() = runBlocking { - val system = npeIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) + val ifds = npeIfdsFacade("ifds", cp, graph, defaultBannedPackagePrefixes) val clazz = cp.findClass() val methods = clazz.declaredMethods - system.runNpeAnalysis(methods, timeout = 20.seconds) - val sinks = system.collectNpeResults() + ifds.runAnalysis(methods, timeout = 20.seconds) + val sinks = ifds.collectFindings() logger.info { "Vulnerabilities found: ${sinks.size}" } } @Test fun `test unused variables analysis`() = runBlocking { - val system = unusedIfdsSystem("ifds", cp, graph, defaultBannedPackagePrefixes) + val ifds = unusedIfdsFacade("ifds", cp, graph, defaultBannedPackagePrefixes) val clazz = cp.findClass() val methods = clazz.declaredMethods - system.runUnusedAnalysis(methods, timeout = 20.seconds) - val sinks = system.collectUnusedResults() + ifds.runAnalysis(methods, timeout = 20.seconds) + val sinks = ifds.collectFindings() logger.info { "Vulnerabilities found: ${sinks.size}" } } } diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt index 4e455276a..2bea5395c 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt @@ -19,7 +19,7 @@ package org.jacodb.analysis.impl import io.mockk.every import io.mockk.mockk import org.jacodb.ifds.common.FlowFunctions -import org.jacodb.ifds.domain.toPath +import org.jacodb.ifds.util.toPath import org.jacodb.ifds.taint.ForwardTaintFlowFunctions import org.jacodb.ifds.taint.TaintDomainFact import org.jacodb.ifds.taint.TaintZeroFact diff --git a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt index c9b88c183..94092d47e 100644 --- a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt +++ b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt @@ -27,6 +27,7 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.encodeToStream import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.ifds.taint.TaintZeroFact import org.jacodb.api.JcClassOrInterface import org.jacodb.api.JcClassProcessingTask @@ -37,19 +38,13 @@ import org.jacodb.ifds.common.ClassChunkStrategy import org.jacodb.ifds.common.MethodChunkStrategy import org.jacodb.ifds.common.PackageChunkStrategy import org.jacodb.ifds.common.SingletonChunkStrategy -import org.jacodb.ifds.npe.collectNpeComputationData -import org.jacodb.ifds.npe.npeIfdsSystem -import org.jacodb.ifds.npe.runNpeAnalysis +import org.jacodb.ifds.npe.npeIfdsFacade import org.jacodb.ifds.result.buildTraceGraph import org.jacodb.ifds.sarif.VulnerabilityInstance import org.jacodb.ifds.sarif.sarifReportFromVulnerabilities import org.jacodb.ifds.sarif.toSarif -import org.jacodb.ifds.taint.collectTaintComputationData -import org.jacodb.ifds.taint.runTaintAnalysis -import org.jacodb.ifds.taint.taintIfdsSystem -import org.jacodb.ifds.unused.collectUnusedResults -import org.jacodb.ifds.unused.runUnusedAnalysis -import org.jacodb.ifds.unused.unusedIfdsSystem +import org.jacodb.ifds.taint.taintIfdsFacade +import org.jacodb.ifds.unused.unusedIfdsFacade import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.impl.features.usagesExt @@ -87,10 +82,15 @@ suspend fun launchAnalysesByConfig( when (analysis) { "NPE" -> { - val system = npeIfdsSystem("ifds", graph.classpath, graph, chunkStrategy = chunkStrategy) - system - .runNpeAnalysis(methods, timeout = 60.seconds) - val data = system.collectNpeComputationData() + val ifds = npeIfdsFacade( + "ifds", + graph.classpath, + graph, + bannedPackagePrefixes = defaultBannedPackagePrefixes, + chunkStrategy = chunkStrategy + ) + ifds.runAnalysis(methods, timeout = 60.seconds) + val data = ifds.collectComputationData() data.findings.map { vulnerability -> val traceGraph = data.buildTraceGraph(vulnerability.vertex, zeroFact = TaintZeroFact) vulnerability.toSarif(traceGraph) @@ -98,16 +98,15 @@ suspend fun launchAnalysesByConfig( } "Unused" -> { - val system = unusedIfdsSystem("ifds", graph.classpath, graph, chunkStrategy = chunkStrategy) - system.runUnusedAnalysis(methods, timeout = 60.seconds) - system.collectUnusedResults().map { it.toSarif() } + val system = unusedIfdsFacade("ifds", graph.classpath, graph, chunkStrategy = chunkStrategy) + system.runAnalysis(methods, timeout = 60.seconds) + system.collectFindings().map { it.toSarif() } } "SQL" -> { - val system = taintIfdsSystem("ifds", graph.classpath, graph, chunkStrategy = chunkStrategy) - system - .runTaintAnalysis(methods, timeout = 60.seconds) - val data = system.collectTaintComputationData() + val ifds = taintIfdsFacade("ifds", graph.classpath, graph, chunkStrategy = chunkStrategy) + ifds.runAnalysis(methods, timeout = 60.seconds) + val data = ifds.collectComputationData() data.findings.map { vulnerability -> val traceGraph = data.buildTraceGraph(vulnerability.vertex, zeroFact = TaintZeroFact) vulnerability.toSarif(traceGraph) From b69f2714a1aaeab47efbd03984328a84f28a490f Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 15 May 2024 01:18:07 +0300 Subject: [PATCH 44/64] [ifds] wip: remove typealiases --- .../kotlin/org/jacodb/ifds/npe/Findings.kt | 3 +-- .../kotlin/org/jacodb/ifds/taint/Findings.kt | 2 +- .../kotlin/org/jacodb/ifds/taint/Types.kt | 25 ------------------- 3 files changed, 2 insertions(+), 28 deletions(-) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Types.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt index 26a6a5ca0..c2a212e43 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt @@ -17,7 +17,6 @@ package org.jacodb.ifds.npe import org.jacodb.ifds.taint.TaintDomainFact -import org.jacodb.ifds.taint.TaintVertex import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.Finding @@ -25,7 +24,7 @@ import org.jacodb.taint.configuration.TaintMethodSink data class NpeVulnerability( val message: String, - val sink: TaintVertex, + val sink: Vertex, val rule: TaintMethodSink? = null, ) : Finding { override val vertex: Vertex diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Findings.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Findings.kt index 480671069..ac308b724 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Findings.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Findings.kt @@ -23,7 +23,7 @@ import org.jacodb.taint.configuration.TaintMethodSink data class TaintVulnerability( val message: String, - val sink: TaintVertex, + val sink: Vertex, val rule: TaintMethodSink? = null, ) : Finding { override val vertex: Vertex = sink diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Types.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Types.kt deleted file mode 100644 index 63ebef0bc..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Types.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.taint - -import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Vertex - - -typealias TaintVertex = Vertex -typealias TaintEdge = Edge From 5ded81bfba00920ad209bfd7c999d09dfa3696e3 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 15 May 2024 15:05:13 +0300 Subject: [PATCH 45/64] [ifds] wip: fix tests --- .../jacodb/actors/impl/ActorSpawnerImpl.kt | 5 +- .../kotlin/org/jacodb/ifds/IfdsContext.kt | 2 +- .../kotlin/org/jacodb/ifds/actors/Runner.kt | 2 +- .../jacodb/ifds/messages/AnalyzerMessages.kt | 5 -- .../org/jacodb/ifds/common/ChunkStrategies.kt | 2 +- .../jacodb/ifds/common/JcAsyncIfdsFacade.kt | 7 +- .../org/jacodb/ifds/common/JcBaseAnalyzer.kt | 7 -- .../org/jacodb/ifds/common/JcChunkResolver.kt | 9 --- .../org/jacodb/ifds/common/JcIfdsContext.kt | 12 ++-- .../org/jacodb/ifds/common/JcIfdsFacade.kt | 32 ++++++---- .../ifds/common/JcIndirectionHandler.kt | 4 +- .../jacodb/ifds/{npe => common}/Runners.kt | 5 +- .../org/jacodb/ifds/config/Condition.kt | 12 ++-- .../kotlin/org/jacodb/ifds/config/Position.kt | 16 ++--- .../org/jacodb/ifds/config/TaintAction.kt | 2 +- .../kotlin/org/jacodb/ifds/npe/Builders.kt | 32 ++-------- .../kotlin/org/jacodb/ifds/npe/Findings.kt | 2 +- .../org/jacodb/ifds/npe/NpeFlowFunctions.kt | 38 +++++------ .../main/kotlin/org/jacodb/ifds/npe/Utils.kt | 6 +- .../org/jacodb/ifds/sarif/Vulnerability.kt | 4 +- .../kotlin/org/jacodb/ifds/taint/Builders.kt | 35 +++------- .../kotlin/org/jacodb/ifds/taint/Runners.kt | 22 ------- .../jacodb/ifds/taint/TaintFlowFunctions.kt | 30 ++++----- .../kotlin/org/jacodb/ifds/unused/Builders.kt | 64 +++++++++++-------- .../kotlin/org/jacodb/ifds/unused/Runners.kt | 21 ------ .../jacodb/ifds/unused/UnusedVariableFacts.kt | 2 +- .../unused/UnusedVariableFlowFunctions.kt | 8 +-- .../kotlin/org/jacodb/ifds/unused/Utils.kt | 4 +- 28 files changed, 155 insertions(+), 235 deletions(-) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/{npe => common}/Runners.kt (86%) delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt delete mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt index 2dbd31d4c..be060ce60 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt @@ -59,12 +59,13 @@ internal class ActorSpawnerImpl( actorFactory: ActorFactory, workerFactory: WorkerFactory, ): ActorWorker { - @Suppress("UNCHECKED_CAST") - val channel = options.channelFactory.create() as Channel if (children[name] != null) { error("$self already has $name child") } + @Suppress("UNCHECKED_CAST") + val channel = options.channelFactory.create() as Channel + val path = self / name val spawner = ActorSpawnerImpl(path, system) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt index aa36b7601..7a56b4bfc 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt @@ -28,6 +28,6 @@ interface IfdsContext { fun chunkByMessage(message: RunnerMessage): Chunk fun runnerIdByMessage(message: RunnerMessage): RunnerId - fun getAnalyzer(chunk: Chunk, runnerId: RunnerId): Analyzer + fun getAnalyzer(runnerId: RunnerId): Analyzer fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId): ActorFactory } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt index 42fa8c206..d86080f61 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt @@ -38,7 +38,7 @@ class Runner( ) : Actor { private val routerFactory = roundRobinRouter(size = 8) { @Suppress("UNCHECKED_CAST") - val analyzer = ifdsContext.getAnalyzer(chunk, runnerId) as Analyzer + val analyzer = ifdsContext.getAnalyzer(runnerId) as Analyzer Worker(analyzer, this@ActorContext.self) } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt index ba8ac92d0..694b86cb3 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt @@ -21,11 +21,6 @@ import org.jacodb.ifds.domain.RunnerId interface AnalyzerMessage : RunnerMessage -data class StartAnalysis( - override val runnerId: RunnerId, - val method: Method, -) : AnalyzerMessage - data class EdgeMessage( override val runnerId: RunnerId, val edge: Edge, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/ChunkStrategies.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/ChunkStrategies.kt index 57a3afc53..0b4d27b5b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/ChunkStrategies.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/ChunkStrategies.kt @@ -38,7 +38,7 @@ val MethodChunkStrategy = ChunkStrategy { stmt -> } data class ClassChunk( - val method: JcClassOrInterface, + val jcClass: JcClassOrInterface, ) : Chunk val ClassChunkStrategy = ChunkStrategy { stmt -> diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt index 1487c16ea..5c3fd80a4 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt @@ -19,21 +19,16 @@ package org.jacodb.ifds.common import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.future.future -import org.jacodb.actors.api.ActorSystem import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.result.Finding import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds class JcAsyncIfdsFacade>( - system: ActorSystem, - startingRunnerId: RunnerId, + private val ifdsFacade: JcIfdsFacade ) { private val scope = CoroutineScope(Job()) - private val ifdsFacade = JcIfdsFacade(system, startingRunnerId) @JvmName("runAnalysis") fun runAnalysis( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt index 83b309664..29ca08b56 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt @@ -31,7 +31,6 @@ import org.jacodb.ifds.messages.NewEdge import org.jacodb.ifds.messages.NotificationOnStart import org.jacodb.ifds.messages.ResolvedCall import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.messages.StartAnalysis import org.jacodb.ifds.messages.SubscriptionOnStart import org.jacodb.ifds.messages.UnresolvedCall @@ -43,12 +42,6 @@ abstract class JcBaseAnalyzer( override fun handle(message: AnalyzerMessage): Collection = buildList { when (message) { - is StartAnalysis<*> -> { - @Suppress("UNCHECKED_CAST") - message as StartAnalysis - processStartAnalysis(message.method) - } - is EdgeMessage -> { processEdge(message.edge) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt index 941634603..8185e63d5 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt @@ -16,7 +16,6 @@ package org.jacodb.ifds.common -import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.ChunkResolver @@ -33,7 +32,6 @@ import org.jacodb.ifds.messages.NotificationOnEnd import org.jacodb.ifds.messages.NotificationOnStart import org.jacodb.ifds.messages.ResolvedCall import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.messages.StartAnalysis import org.jacodb.ifds.messages.StorageMessage import org.jacodb.ifds.messages.SubscriptionOnEnd import org.jacodb.ifds.messages.SubscriptionOnStart @@ -68,13 +66,6 @@ class JcChunkResolver( chunkStrategy.chunkByStmt(message.edge.to.statement) } - is StartAnalysis<*> -> { - message as StartAnalysis - - val stmt = graph.entryPoints(message.method).first() - chunkStrategy.chunkByStmt(stmt) - } - else -> { error("Unexpected message: $message") } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt index 1c5e5d210..f20d1571a 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt @@ -16,23 +16,23 @@ package org.jacodb.ifds.common -import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorFactory +import org.jacodb.actors.api.ActorRef import org.jacodb.api.JcClasspath import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.ChunkResolver import org.jacodb.ifds.IfdsContext -import org.jacodb.ifds.domain.Analyzer import org.jacodb.ifds.domain.Chunk import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.impl.features.HierarchyExtensionImpl +import java.util.concurrent.ConcurrentHashMap class JcIfdsContext( private val cp: JcClasspath, private val bannedPackagePrefixes: List, private val chunkStrategy: ChunkResolver, - private val analyzerFactory: (RunnerId) -> Analyzer, + private val analyzerFactory: (RunnerId) -> JcBaseAnalyzer, ) : IfdsContext { override fun chunkByMessage(message: RunnerMessage): Chunk = chunkStrategy.chunkByMessage(message) @@ -40,8 +40,10 @@ class JcIfdsContext( override fun runnerIdByMessage(message: RunnerMessage): RunnerId = message.runnerId - override fun getAnalyzer(chunk: Chunk, runnerId: RunnerId): Analyzer = - analyzerFactory(runnerId) + private val analyzers = ConcurrentHashMap>() + + override fun getAnalyzer(runnerId: RunnerId): JcBaseAnalyzer = + analyzers.computeIfAbsent(runnerId, analyzerFactory) override fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId) = ActorFactory { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt index 115df9064..768f20c1c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt @@ -20,8 +20,8 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.jacodb.actors.api.ActorSystem -import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.api.JcMethod +import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Edge import org.jacodb.ifds.domain.Reason @@ -30,22 +30,19 @@ import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.messages.CollectAllData import org.jacodb.ifds.messages.CommonMessage import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.StartAnalysis -import org.jacodb.ifds.npe.NpeAnalyzer -import org.jacodb.ifds.npe.SingletonRunnerId import org.jacodb.ifds.result.Finding import org.jacodb.ifds.result.IfdsComputationData import org.jacodb.ifds.result.mergeIfdsResults -import org.jacodb.ifds.taint.ForwardRunnerId -import org.jacodb.impl.features.usagesExt import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds -class JcIfdsFacade>( +open class JcIfdsFacade>( + private val graph: JcApplicationGraph, + private val context: JcIfdsContext, private val system: ActorSystem, private val startingRunnerId: RunnerId, ) { - suspend fun runAnalysis( + open suspend fun runAnalysis( methods: Collection, timeout: Duration = 60.seconds, ) = coroutineScope { @@ -62,22 +59,29 @@ class JcIfdsFacade>( system.resume() } - suspend fun startAnalysis( + open suspend fun startAnalysis( method: JcMethod, ) { - val message = StartAnalysis(startingRunnerId, method) - system.send(message) + val analyzer = context.getAnalyzer(startingRunnerId) + for (fact in analyzer.obtainPossibleStartFacts(method)) { + for (entryPoint in graph.entryPoints(method)) { + val vertex = Vertex(entryPoint, fact) + val edge = Edge(vertex, vertex) + val newEdgeMessage = NewEdge(startingRunnerId, edge, Reason.Initial) + system.send(newEdgeMessage) + } + } } suspend fun awaitAnalysis() { system.awaitCompletion() } - suspend fun collectFindings(): Collection = + open suspend fun collectFindings(): Collection = collectComputationData().findings - suspend fun collectComputationData(): IfdsComputationData { - val results = system.ask { CollectAllData(SingletonRunnerId, it) } + open suspend fun collectComputationData(): IfdsComputationData { + val results = system.ask { CollectAllData(startingRunnerId, it) } @Suppress("UNCHECKED_CAST") val ifdsData = results.values as Collection> diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt index 7b37af304..15d798ab3 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt @@ -19,7 +19,6 @@ package org.jacodb.ifds.common import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef -import org.jacodb.ifds.taint.TaintDomainFact import org.jacodb.api.JcClassType import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst @@ -28,10 +27,11 @@ import org.jacodb.api.ext.HierarchyExtension import org.jacodb.api.ext.cfg.callExpr import org.jacodb.api.ext.isSubClassOf import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.IndirectionMessage import org.jacodb.ifds.messages.ResolvedCall +import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.UnresolvedCall +import org.jacodb.ifds.taint.TaintDomainFact context(ActorContext) class JcIndirectionHandler( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/Runners.kt similarity index 86% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/Runners.kt index 5ce7ed09e..ed26da7b3 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/Runners.kt @@ -14,8 +14,11 @@ * limitations under the License. */ -package org.jacodb.ifds.npe +package org.jacodb.ifds.common import org.jacodb.ifds.domain.RunnerId data object SingletonRunnerId : RunnerId + +data object ForwardRunnerId : RunnerId +data object BackwardRunnerId : RunnerId \ No newline at end of file diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt index a50a66ea8..efd0d3d94 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt @@ -16,18 +16,18 @@ package org.jacodb.ifds.config -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.ElementAccessor -import org.jacodb.ifds.util.Maybe -import org.jacodb.ifds.util.onSome -import org.jacodb.ifds.util.toPath -import org.jacodb.ifds.taint.Tainted import org.jacodb.api.cfg.JcBool import org.jacodb.api.cfg.JcConstant import org.jacodb.api.cfg.JcInt import org.jacodb.api.cfg.JcStringConstant import org.jacodb.api.cfg.JcValue import org.jacodb.api.ext.isAssignable +import org.jacodb.ifds.taint.Tainted +import org.jacodb.ifds.util.AccessPath +import org.jacodb.ifds.util.ElementAccessor +import org.jacodb.ifds.util.Maybe +import org.jacodb.ifds.util.onSome +import org.jacodb.ifds.util.toPath import org.jacodb.taint.configuration.And import org.jacodb.taint.configuration.AnnotationType import org.jacodb.taint.configuration.ConditionVisitor diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt index be79483cc..de14f0ea5 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt @@ -16,14 +16,6 @@ package org.jacodb.ifds.config -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.ElementAccessor -import org.jacodb.ifds.util.Maybe -import org.jacodb.ifds.util.fmap -import org.jacodb.ifds.util.toMaybe -import org.jacodb.ifds.util.toPathOrNull -import org.jacodb.ifds.util.getArgument -import org.jacodb.ifds.util.thisInstance import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcAssignInst @@ -31,6 +23,14 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.api.cfg.JcInstanceCallExpr import org.jacodb.api.cfg.JcValue import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.ifds.util.AccessPath +import org.jacodb.ifds.util.ElementAccessor +import org.jacodb.ifds.util.Maybe +import org.jacodb.ifds.util.fmap +import org.jacodb.ifds.util.getArgument +import org.jacodb.ifds.util.thisInstance +import org.jacodb.ifds.util.toMaybe +import org.jacodb.ifds.util.toPathOrNull import org.jacodb.taint.configuration.AnyArgument import org.jacodb.taint.configuration.Argument import org.jacodb.taint.configuration.Position diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt index 89b96c826..34b36c099 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt @@ -16,11 +16,11 @@ package org.jacodb.ifds.config +import org.jacodb.ifds.taint.Tainted import org.jacodb.ifds.util.AccessPath import org.jacodb.ifds.util.Maybe import org.jacodb.ifds.util.fmap import org.jacodb.ifds.util.map -import org.jacodb.ifds.taint.Tainted import org.jacodb.taint.configuration.AssignMark import org.jacodb.taint.configuration.CopyAllMarks import org.jacodb.taint.configuration.CopyMark diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt index 59169bf4f..2c95da80b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt @@ -16,20 +16,19 @@ package org.jacodb.ifds.npe -import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.common.JcChunkResolver import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.common.ClassChunkStrategy import org.jacodb.ifds.common.JcAsyncIfdsFacade +import org.jacodb.ifds.common.JcChunkResolver import org.jacodb.ifds.common.JcIfdsContext import org.jacodb.ifds.common.JcIfdsFacade -import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.common.SingletonRunnerId import org.jacodb.ifds.taint.TaintDomainFact fun npeIfdsContext( @@ -51,24 +50,6 @@ fun npeIfdsContext( analyzer } -fun npeIfdsSystem( - name: String, - cp: JcClasspath, - graph: JcApplicationGraph, - bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, -): ActorSystem { - val context = npeIfdsContext( - cp, - graph, - bannedPackagePrefixes, - chunkStrategy - ) - return system(name) { - ProjectManager(context) - } -} - fun npeIfdsFacade( name: String, cp: JcClasspath, @@ -76,8 +57,9 @@ fun npeIfdsFacade( bannedPackagePrefixes: List = defaultBannedPackagePrefixes, chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsFacade { - val system = npeIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) - return JcIfdsFacade(system, SingletonRunnerId) + val context = npeIfdsContext(cp, graph, bannedPackagePrefixes, chunkStrategy) + val system = system(name) { ProjectManager(context) } + return JcIfdsFacade(graph, context, system, SingletonRunnerId) } fun asyncNpeIfdsFacade( @@ -87,6 +69,6 @@ fun asyncNpeIfdsFacade( bannedPackagePrefixes: List = defaultBannedPackagePrefixes, chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcAsyncIfdsFacade { - val system = npeIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) - return JcAsyncIfdsFacade(system, SingletonRunnerId) + val facade = npeIfdsFacade(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + return JcAsyncIfdsFacade(facade) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt index c2a212e43..532942648 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt @@ -16,10 +16,10 @@ package org.jacodb.ifds.npe -import org.jacodb.ifds.taint.TaintDomainFact import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.domain.Vertex import org.jacodb.ifds.result.Finding +import org.jacodb.ifds.taint.TaintDomainFact import org.jacodb.taint.configuration.TaintMethodSink data class NpeVulnerability( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt index 69e9e1251..00291ce07 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt @@ -16,25 +16,6 @@ package org.jacodb.ifds.npe -import org.jacodb.ifds.config.BasicConditionEvaluator -import org.jacodb.ifds.config.CallPositionToAccessPathResolver -import org.jacodb.ifds.config.CallPositionToJcValueResolver -import org.jacodb.ifds.config.EntryPointPositionToAccessPathResolver -import org.jacodb.ifds.config.EntryPointPositionToJcValueResolver -import org.jacodb.ifds.config.FactAwareConditionEvaluator -import org.jacodb.ifds.config.TaintActionEvaluator -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.ElementAccessor -import org.jacodb.ifds.common.FlowFunctions -import org.jacodb.ifds.util.onSome -import org.jacodb.ifds.util.toPath -import org.jacodb.ifds.util.toPathOrNull -import org.jacodb.ifds.taint.TaintDomainFact -import org.jacodb.ifds.taint.TaintZeroFact -import org.jacodb.ifds.taint.Tainted -import org.jacodb.ifds.util.getArgumentsOf -import org.jacodb.ifds.util.startsWith -import org.jacodb.ifds.util.thisInstance import org.jacodb.api.JcArrayType import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod @@ -57,6 +38,25 @@ import org.jacodb.api.cfg.JcValue import org.jacodb.api.ext.cfg.callExpr import org.jacodb.api.ext.findTypeOrNull import org.jacodb.api.ext.isNullable +import org.jacodb.ifds.common.FlowFunctions +import org.jacodb.ifds.config.BasicConditionEvaluator +import org.jacodb.ifds.config.CallPositionToAccessPathResolver +import org.jacodb.ifds.config.CallPositionToJcValueResolver +import org.jacodb.ifds.config.EntryPointPositionToAccessPathResolver +import org.jacodb.ifds.config.EntryPointPositionToJcValueResolver +import org.jacodb.ifds.config.FactAwareConditionEvaluator +import org.jacodb.ifds.config.TaintActionEvaluator +import org.jacodb.ifds.taint.TaintDomainFact +import org.jacodb.ifds.taint.TaintZeroFact +import org.jacodb.ifds.taint.Tainted +import org.jacodb.ifds.util.AccessPath +import org.jacodb.ifds.util.ElementAccessor +import org.jacodb.ifds.util.getArgumentsOf +import org.jacodb.ifds.util.onSome +import org.jacodb.ifds.util.startsWith +import org.jacodb.ifds.util.thisInstance +import org.jacodb.ifds.util.toPath +import org.jacodb.ifds.util.toPathOrNull import org.jacodb.taint.configuration.AssignMark import org.jacodb.taint.configuration.CopyAllMarks import org.jacodb.taint.configuration.CopyMark diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt index 513267c56..31283d701 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt @@ -16,14 +16,14 @@ package org.jacodb.ifds.npe -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.toPathOrNull -import org.jacodb.ifds.util.startsWith import org.jacodb.api.cfg.JcExpr import org.jacodb.api.cfg.JcInst import org.jacodb.api.cfg.JcInstanceCallExpr import org.jacodb.api.cfg.JcLengthExpr import org.jacodb.api.cfg.values +import org.jacodb.ifds.util.AccessPath +import org.jacodb.ifds.util.startsWith +import org.jacodb.ifds.util.toPathOrNull fun AccessPath?.isDereferencedAt(expr: JcExpr): Boolean { if (this == null) { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt index 5e0f4f21d..a2c4e60b2 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt @@ -17,13 +17,13 @@ package org.jacodb.ifds.sarif import io.github.detekt.sarif4k.Level -import org.jacodb.ifds.taint.TaintDomainFact -import org.jacodb.ifds.unused.UnusedVariableDomainFact import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.npe.NpeVulnerability import org.jacodb.ifds.result.EagerTraceGraph import org.jacodb.ifds.result.TraceGraph +import org.jacodb.ifds.taint.TaintDomainFact import org.jacodb.ifds.taint.TaintVulnerability +import org.jacodb.ifds.unused.UnusedVariableDomainFact import org.jacodb.ifds.unused.UnusedVulnerability data class VulnerabilityInstance( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt index 20964bd1e..00736bf11 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt @@ -16,20 +16,20 @@ package org.jacodb.ifds.taint -import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.common.JcChunkResolver import org.jacodb.ifds.actors.ProjectManager +import org.jacodb.ifds.common.BackwardRunnerId +import org.jacodb.ifds.common.ClassChunkStrategy +import org.jacodb.ifds.common.ForwardRunnerId import org.jacodb.ifds.common.JcAsyncIfdsFacade +import org.jacodb.ifds.common.JcChunkResolver import org.jacodb.ifds.common.JcIfdsContext import org.jacodb.ifds.common.JcIfdsFacade -import org.jacodb.ifds.messages.CommonMessage fun taintIfdsContext( cp: JcClasspath, @@ -49,24 +49,6 @@ fun taintIfdsContext( } } -fun taintIfdsSystem( - name: String, - cp: JcClasspath, - graph: JcApplicationGraph, - bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, -): ActorSystem { - val context = taintIfdsContext( - cp, - graph, - bannedPackagePrefixes, - chunkStrategy - ) - return system(name) { - ProjectManager(context) - } -} - fun taintIfdsFacade( name: String, cp: JcClasspath, @@ -74,8 +56,9 @@ fun taintIfdsFacade( bannedPackagePrefixes: List = defaultBannedPackagePrefixes, chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsFacade { - val system = taintIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) - return JcIfdsFacade(system, ForwardRunnerId) + val context = taintIfdsContext(cp, graph, bannedPackagePrefixes, chunkStrategy) + val system = system(name) { ProjectManager(context) } + return JcIfdsFacade(graph, context, system, ForwardRunnerId) } fun asyncTaintIfdsFacade( @@ -85,6 +68,6 @@ fun asyncTaintIfdsFacade( bannedPackagePrefixes: List = defaultBannedPackagePrefixes, chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcAsyncIfdsFacade { - val system = taintIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) - return JcAsyncIfdsFacade(system, ForwardRunnerId) + val facade = taintIfdsFacade(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + return JcAsyncIfdsFacade(facade) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt deleted file mode 100644 index 42339ff21..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Runners.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.taint - -import org.jacodb.ifds.domain.RunnerId - -data object ForwardRunnerId : RunnerId -data object BackwardRunnerId : RunnerId diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt index 4a5c2e538..08b9fda5c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt @@ -16,21 +16,6 @@ package org.jacodb.ifds.taint -import org.jacodb.ifds.config.BasicConditionEvaluator -import org.jacodb.ifds.config.CallPositionToAccessPathResolver -import org.jacodb.ifds.config.CallPositionToJcValueResolver -import org.jacodb.ifds.config.EntryPointPositionToAccessPathResolver -import org.jacodb.ifds.config.EntryPointPositionToJcValueResolver -import org.jacodb.ifds.config.FactAwareConditionEvaluator -import org.jacodb.ifds.config.TaintActionEvaluator -import org.jacodb.ifds.util.ElementAccessor -import org.jacodb.ifds.common.FlowFunctions -import org.jacodb.ifds.util.onSome -import org.jacodb.ifds.util.toPath -import org.jacodb.ifds.util.toPathOrNull -import org.jacodb.ifds.util.getArgumentsOf -import org.jacodb.ifds.util.startsWith -import org.jacodb.ifds.util.thisInstance import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph @@ -44,6 +29,21 @@ import org.jacodb.api.cfg.JcReturnInst import org.jacodb.api.cfg.JcThis import org.jacodb.api.cfg.JcValue import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.ifds.common.FlowFunctions +import org.jacodb.ifds.config.BasicConditionEvaluator +import org.jacodb.ifds.config.CallPositionToAccessPathResolver +import org.jacodb.ifds.config.CallPositionToJcValueResolver +import org.jacodb.ifds.config.EntryPointPositionToAccessPathResolver +import org.jacodb.ifds.config.EntryPointPositionToJcValueResolver +import org.jacodb.ifds.config.FactAwareConditionEvaluator +import org.jacodb.ifds.config.TaintActionEvaluator +import org.jacodb.ifds.util.ElementAccessor +import org.jacodb.ifds.util.getArgumentsOf +import org.jacodb.ifds.util.onSome +import org.jacodb.ifds.util.startsWith +import org.jacodb.ifds.util.thisInstance +import org.jacodb.ifds.util.toPath +import org.jacodb.ifds.util.toPathOrNull import org.jacodb.taint.configuration.AssignMark import org.jacodb.taint.configuration.CopyAllMarks import org.jacodb.taint.configuration.CopyMark diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt index 64404fc88..08a10d937 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt @@ -16,20 +16,20 @@ package org.jacodb.ifds.unused -import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.common.JcChunkResolver import org.jacodb.ifds.actors.ProjectManager import org.jacodb.ifds.common.ClassChunkStrategy import org.jacodb.ifds.common.JcAsyncIfdsFacade +import org.jacodb.ifds.common.JcChunkResolver import org.jacodb.ifds.common.JcIfdsContext import org.jacodb.ifds.common.JcIfdsFacade -import org.jacodb.ifds.messages.CommonMessage +import org.jacodb.ifds.common.SingletonRunnerId +import org.jacodb.ifds.domain.Vertex fun unusedIfdsContext( cp: JcClasspath, @@ -48,24 +48,6 @@ fun unusedIfdsContext( } } -fun unusedIfdsSystem( - name: String, - cp: JcClasspath, - graph: JcApplicationGraph, - bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, -): ActorSystem { - val context = unusedIfdsContext( - cp, - graph, - bannedPackagePrefixes, - chunkStrategy - ) - return system(name) { - ProjectManager(context) - } -} - fun unusedIfdsFacade( name: String, cp: JcClasspath, @@ -73,8 +55,40 @@ fun unusedIfdsFacade( bannedPackagePrefixes: List = defaultBannedPackagePrefixes, chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsFacade { - val system = unusedIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) - return JcIfdsFacade(system, SingletonRunnerId) + val context = unusedIfdsContext(cp, graph, bannedPackagePrefixes, chunkStrategy) + val system = system(name) { ProjectManager(context) } + return object : JcIfdsFacade( + graph, + context, + system, + SingletonRunnerId + ) { + override suspend fun collectFindings(): Collection { + val data = collectComputationData() + + val allFacts = data.factsByStmt + + val used = hashMapOf() + for ((inst, facts) in allFacts) { + for (fact in facts) { + if (fact is UnusedVariable) { + used.putIfAbsent(fact.initStatement, false) + if (fact.variable.isUsedAt(inst)) { + used[fact.initStatement] = true + } + } + + } + } + val vulnerabilities = used.filterValues { !it }.keys.map { + UnusedVulnerability( + message = "Assigned value is unused", + sink = Vertex(it, UnusedVariableZeroFact) + ) + } + return vulnerabilities + } + } } fun asyncUnusedIfdsFacade( @@ -84,6 +98,6 @@ fun asyncUnusedIfdsFacade( bannedPackagePrefixes: List = defaultBannedPackagePrefixes, chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcAsyncIfdsFacade { - val system = unusedIfdsSystem(name, cp, graph, bannedPackagePrefixes, chunkStrategy) - return JcAsyncIfdsFacade(system, SingletonRunnerId) + val facade = unusedIfdsFacade(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + return JcAsyncIfdsFacade(facade) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt deleted file mode 100644 index 5f0370017..000000000 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Runners.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -package org.jacodb.ifds.unused - -import org.jacodb.ifds.domain.RunnerId - -data object SingletonRunnerId : RunnerId diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt index abaecfb72..7215c5696 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt @@ -16,8 +16,8 @@ package org.jacodb.ifds.unused -import org.jacodb.ifds.util.AccessPath import org.jacodb.api.cfg.JcInst +import org.jacodb.ifds.util.AccessPath sealed interface UnusedVariableDomainFact diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt index 62f183960..706500a9a 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt @@ -16,10 +16,6 @@ package org.jacodb.ifds.unused -import org.jacodb.ifds.common.FlowFunctions -import org.jacodb.ifds.util.toPath -import org.jacodb.ifds.util.toPathOrNull -import org.jacodb.ifds.util.getArgumentsOf import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcAssignInst @@ -27,6 +23,10 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.api.cfg.JcSpecialCallExpr import org.jacodb.api.cfg.JcStaticCallExpr import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.ifds.common.FlowFunctions +import org.jacodb.ifds.util.getArgumentsOf +import org.jacodb.ifds.util.toPath +import org.jacodb.ifds.util.toPathOrNull class UnusedVariableFlowFunctions( private val graph: JcApplicationGraph, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt index ee4dca5bf..2eb940ee3 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt @@ -16,8 +16,6 @@ package org.jacodb.ifds.unused -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.toPathOrNull import org.jacodb.api.cfg.JcArrayAccess import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcBranchingInst @@ -28,6 +26,8 @@ import org.jacodb.api.cfg.JcSpecialCallExpr import org.jacodb.api.cfg.JcTerminatingInst import org.jacodb.api.cfg.values import org.jacodb.api.ext.cfg.callExpr +import org.jacodb.ifds.util.AccessPath +import org.jacodb.ifds.util.toPathOrNull internal fun AccessPath.isUsedAt(expr: JcExpr): Boolean { return expr.values.any { it.toPathOrNull() == this } From 3f153a38a7d8082777f071b153bd8666189167ac Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 15 May 2024 16:57:32 +0300 Subject: [PATCH 46/64] [ifds] wip: refactored indirection handler a bit --- .../kotlin/org/jacodb/ifds/IfdsContext.kt | 6 +-- .../ifds/actors/IndirectionHandlerActor.kt | 37 +++++++++++++++++++ .../kotlin/org/jacodb/ifds/actors/Runner.kt | 6 ++- .../jacodb/ifds/domain/IndirectionHandler.kt | 24 ++++++++++++ .../org/jacodb/ifds/common/JcIfdsContext.kt | 9 ++--- .../ifds/common/JcIndirectionHandler.kt | 37 ++++++------------- 6 files changed, 81 insertions(+), 38 deletions(-) create mode 100644 jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/IndirectionHandlerActor.kt create mode 100644 jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/IndirectionHandler.kt diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt index 7a56b4bfc..da5cea814 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt @@ -16,12 +16,10 @@ package org.jacodb.ifds -import org.jacodb.actors.api.ActorFactory -import org.jacodb.actors.api.ActorRef import org.jacodb.ifds.domain.Analyzer import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.domain.IndirectionHandler import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.IndirectionMessage import org.jacodb.ifds.messages.RunnerMessage interface IfdsContext { @@ -29,5 +27,5 @@ interface IfdsContext { fun runnerIdByMessage(message: RunnerMessage): RunnerId fun getAnalyzer(runnerId: RunnerId): Analyzer - fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId): ActorFactory + fun getIndirectionHandler(runnerId: RunnerId): IndirectionHandler } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/IndirectionHandlerActor.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/IndirectionHandlerActor.kt new file mode 100644 index 000000000..c83190350 --- /dev/null +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/IndirectionHandlerActor.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.actors + +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.api.ActorRef +import org.jacodb.ifds.domain.IndirectionHandler +import org.jacodb.ifds.messages.IndirectionMessage +import org.jacodb.ifds.messages.RunnerMessage + +context(ActorContext) +class IndirectionHandlerActor( + private val parent: ActorRef, + private val indirectionHandler: IndirectionHandler, +) : Actor { + override suspend fun receive(message: IndirectionMessage) { + val newMessages = indirectionHandler.handle(message) + for (newMessage in newMessages) { + parent.send(newMessage) + } + } +} \ No newline at end of file diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt index d86080f61..5c212c64a 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt @@ -50,8 +50,10 @@ class Runner( private val indirectionHandler = spawn( "indirection", - actorFactory = ifdsContext.indirectionHandlerFactory(this@ActorContext.self, runnerId) - ) + ) { + val indirectionHandler = ifdsContext.getIndirectionHandler(runnerId) + IndirectionHandlerActor(this@ActorContext.self, indirectionHandler) + } override suspend fun receive(message: RunnerMessage) { when { diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/IndirectionHandler.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/IndirectionHandler.kt new file mode 100644 index 000000000..8fcfceece --- /dev/null +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/IndirectionHandler.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.ifds.domain + +import org.jacodb.ifds.messages.IndirectionMessage +import org.jacodb.ifds.messages.RunnerMessage + +interface IndirectionHandler { + fun handle(message: IndirectionMessage): Collection +} \ No newline at end of file diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt index f20d1571a..ad1177cd8 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt @@ -16,13 +16,12 @@ package org.jacodb.ifds.common -import org.jacodb.actors.api.ActorFactory -import org.jacodb.actors.api.ActorRef import org.jacodb.api.JcClasspath import org.jacodb.api.cfg.JcInst import org.jacodb.ifds.ChunkResolver import org.jacodb.ifds.IfdsContext import org.jacodb.ifds.domain.Chunk +import org.jacodb.ifds.domain.IndirectionHandler import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.impl.features.HierarchyExtensionImpl @@ -45,8 +44,6 @@ class JcIfdsContext( override fun getAnalyzer(runnerId: RunnerId): JcBaseAnalyzer = analyzers.computeIfAbsent(runnerId, analyzerFactory) - override fun indirectionHandlerFactory(parent: ActorRef, runnerId: RunnerId) = - ActorFactory { - JcIndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, parent, runnerId) - } + override fun getIndirectionHandler(runnerId: RunnerId): IndirectionHandler = + JcIndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, runnerId) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt index 15d798ab3..42ecb905e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt @@ -16,9 +16,6 @@ package org.jacodb.ifds.common -import org.jacodb.actors.api.Actor -import org.jacodb.actors.api.ActorContext -import org.jacodb.actors.api.ActorRef import org.jacodb.api.JcClassType import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst @@ -26,6 +23,7 @@ import org.jacodb.api.cfg.JcVirtualCallExpr import org.jacodb.api.ext.HierarchyExtension import org.jacodb.api.ext.cfg.callExpr import org.jacodb.api.ext.isSubClassOf +import org.jacodb.ifds.domain.IndirectionHandler import org.jacodb.ifds.domain.RunnerId import org.jacodb.ifds.messages.IndirectionMessage import org.jacodb.ifds.messages.ResolvedCall @@ -33,41 +31,32 @@ import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.ifds.messages.UnresolvedCall import org.jacodb.ifds.taint.TaintDomainFact -context(ActorContext) class JcIndirectionHandler( private val hierarchy: HierarchyExtension, private val bannedPackagePrefixes: List, - private val parent: ActorRef, private val runnerId: RunnerId, -) : Actor { +) : IndirectionHandler { private val cache = hashMapOf>() - override suspend fun receive(message: IndirectionMessage) { - // TODO: refactor it + + override fun handle(message: IndirectionMessage): Collection { @Suppress("UNCHECKED_CAST") - message as? UnresolvedCall ?: return + message as? UnresolvedCall ?: return emptyList() val node = message.edge.to.statement - val callees = (node.callExpr?.let { sequenceOf(it.method.method) } ?: emptySequence()) + val callees = (node.callExpr?.let { listOf(it.method.method) } ?: emptyList()) .filterNot { callee -> bannedPackagePrefixes.any { callee.enclosingClass.name.startsWith(it) } } val callExpr = node.callExpr as? JcVirtualCallExpr - if (callExpr == null) { - for (override in callees) { - parent.send(ResolvedCall(runnerId, message.edge, override)) - } - return - } + ?: return callees.map { ResolvedCall(runnerId, message.edge, it) } + val instanceClass = (callExpr.instance.type as? JcClassType)?.jcClass - if (instanceClass == null) { - parent.send(ResolvedCall(runnerId, message.edge, callExpr.method.method)) - return - } + ?: return listOf(ResolvedCall(runnerId, message.edge, callExpr.method.method)) - val overrides = callees + return callees .flatMap { callee -> val allOverrides = cache.computeIfAbsent(callee) { hierarchy.findOverrides(callee).toList() @@ -78,10 +67,6 @@ class JcIndirectionHandler( }.asSequence() // TODO: maybe filter inaccessible methods here? allOverrides + sequenceOf(callee) - } - - for (override in overrides) { - parent.send(ResolvedCall(runnerId, message.edge, override)) - } + }.mapTo(mutableListOf()) { ResolvedCall(runnerId, message.edge, it) } } } From d237955070c6f9b1ec78076a568d8b553bd67768 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 15 May 2024 21:42:30 +0300 Subject: [PATCH 47/64] [ifds] wip: closing actor system --- .../main/kotlin/org/jacodb/actors/api/ActorSystem.kt | 2 +- .../kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt index f315db41c..d19a19fb1 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorSystem.kt @@ -19,7 +19,7 @@ package org.jacodb.actors.api import kotlinx.coroutines.CompletableDeferred import mu.KLogger -interface ActorSystem { +interface ActorSystem : AutoCloseable { val name: String suspend fun send(message: Message) diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 27d5fb9b5..82e7086e4 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -18,7 +18,9 @@ package org.jacodb.actors.impl import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel import mu.KLogger import mu.KotlinLogging.logger import org.jacodb.actors.api.ActorFactory @@ -31,14 +33,14 @@ internal class ActorSystemImpl( override val name: String, options: SpawnOptions, actorFactory: ActorFactory, -) : ActorSystem { +) : ActorSystem, AutoCloseable { private val path = root() / name override val logger: KLogger = logger(path.toString()) private val spawner = ActorSpawnerImpl(path, this) - internal val scope = CoroutineScope(SupervisorJob()) + internal val scope = CoroutineScope(Job()) internal val watcher = spawner.spawnInternalActor(WATCHER_ACTOR_NAME, SpawnOptions.default, ::WatcherActor) @@ -77,6 +79,10 @@ internal class ActorSystemImpl( private const val USER_ACTOR_NAME = "usr" private const val WATCHER_ACTOR_NAME = "watcher" } + + override fun close() { + scope.cancel() + } } fun system( From 08e4defd05bbb84a25b4014b062ede4212d166ad Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 15 May 2024 22:23:59 +0300 Subject: [PATCH 48/64] [ifds] wip: restructure packages --- jacodb-analysis/README.md | 2 + .../org/jacodb/actors/impl/ActorSystemImpl.kt | 1 - .../actors/impl/workers/UserActorWorker.kt | 1 - jacodb-analysis/common/build.gradle.kts | 16 +++++ .../analysis}/custom/AbstractFlowAnalysis.kt | 2 +- .../analysis}/custom/BackwardFlowAnalysis.kt | 2 +- .../jacodb/analysis}/custom/FlowAnalysis.kt | 2 +- .../analysis}/custom/FlowAnalysisImpl.kt | 2 +- .../analysis}/custom/ForwardFlowAnalysis.kt | 2 +- .../custom/NullAssumptionAnalysis.kt | 2 +- .../custom/ReachingDefinitionsAnalysis.kt | 5 +- .../analysis/graph/ApplicationGraphFactory.kt | 0 .../jacodb/analysis/graph/BackwardGraphs.kt | 0 .../analysis/graph/JcApplicationGraphImpl.kt | 0 .../NullabilityAssumptionAnalysisTest.kt | 3 +- jacodb-analysis/ifds/build.gradle.kts | 3 +- .../{ => analysis}/ifds/ChunkResolver.kt | 6 +- .../jacodb/{ => analysis}/ifds/IfdsContext.kt | 12 ++-- .../ifds/actors/ChunkManager.kt | 15 +++-- .../ifds/actors/IndirectionHandlerActor.kt | 8 +-- .../ifds/actors/ProjectManager.kt | 25 ++++---- .../{ => analysis}/ifds/actors/Runner.kt | 19 +++--- .../ifds/actors/RunnerStorage.kt | 38 ++++++------ .../{ => analysis}/ifds/actors/Worker.kt | 8 +-- .../{ => analysis}/ifds/domain/Analyzer.kt | 6 +- .../{ => analysis}/ifds/domain/Chunk.kt | 2 +- .../jacodb/{ => analysis}/ifds/domain/Edge.kt | 2 +- .../ifds/domain/IndirectionHandler.kt | 6 +- .../{ => analysis}/ifds/domain/Reason.kt | 2 +- .../{ => analysis}/ifds/domain/RunnerId.kt | 2 +- .../{ => analysis}/ifds/domain/Vertex.kt | 2 +- .../ifds/messages/AnalyzerMessages.kt | 11 +++- .../ifds/messages/CommonMessage.kt | 2 +- .../ifds/messages/IndirectionMessages.kt | 6 +- .../ifds/messages/ProjectMessages.kt | 8 +-- .../ifds/messages/RunnerMessage.kt | 4 +- .../ifds/messages/StorageMessages.kt | 16 ++--- .../ifds/result/EagerTraceGraph.kt | 8 +-- .../{ => analysis}/ifds/result/Finding.kt | 4 +- .../ifds/result/IfdsComputationData.kt | 8 +-- .../{ => analysis}/ifds/result/Merging.kt | 8 +-- .../{ => analysis}/ifds/result/TraceGraph.kt | 4 +- jacodb-analysis/taint/build.gradle.kts | 1 - .../ifds/common/ChunkStrategies.kt | 15 +++-- .../ifds/common/FlowFunctions.kt | 10 +++- .../ifds/common/JcAsyncIfdsFacade.kt | 12 ++-- .../ifds/common/JcBaseAnalyzer.kt | 59 ++++++++----------- .../ifds/common/JcChunkResolver.kt | 40 ++++++------- .../ifds/common/JcIfdsContext.kt | 16 +++-- .../ifds/common/JcIfdsFacade.kt | 32 +++++----- .../ifds/common/JcIndirectionHandler.kt | 16 ++--- .../{ => analysis}/ifds/common/Runners.kt | 4 +- .../{ => analysis}/ifds/config/Condition.kt | 16 ++--- .../{ => analysis}/ifds/config/Position.kt | 18 +++--- .../{ => analysis}/ifds/config/TaintAction.kt | 12 ++-- .../{ => analysis}/ifds/npe/Builders.kt | 25 ++++---- .../{ => analysis}/ifds/npe/Findings.kt | 8 +-- .../{ => analysis}/ifds/npe/NpeAnalyzers.kt | 29 ++++----- .../ifds/npe/NpeFlowFunctions.kt | 46 +++++++-------- .../jacodb/{ => analysis}/ifds/npe/Utils.kt | 8 +-- .../jacodb/{ => analysis}/ifds/sarif/Sarif.kt | 4 +- .../ifds/sarif/SourceFileResolver.kt | 2 +- .../ifds/sarif/Vulnerability.kt | 16 ++--- .../{ => analysis}/ifds/taint/Builders.kt | 25 ++++---- .../{ => analysis}/ifds/taint/Findings.kt | 6 +- .../ifds/taint/TaintAnalyzers.kt | 23 +++----- .../{ => analysis}/ifds/taint/TaintFacts.kt | 4 +- .../ifds/taint/TaintFlowFunctions.kt | 42 ++++++------- .../{ => analysis}/ifds/unused/Builders.kt | 25 ++++---- .../{ => analysis}/ifds/unused/Findings.kt | 6 +- .../ifds/unused/UnusedVariableAnalyzer.kt | 16 ++--- .../ifds/unused/UnusedVariableFacts.kt | 4 +- .../unused/UnusedVariableFlowFunctions.kt | 24 ++++---- .../{ => analysis}/ifds/unused/Utils.kt | 6 +- .../{ => analysis}/ifds/util/AccessPath.kt | 2 +- .../{ => analysis}/ifds/util/Accessors.kt | 2 +- .../{ => analysis}/ifds/util/Extensions.kt | 2 +- .../jacodb/{ => analysis}/ifds/util/Maybe.kt | 2 +- .../{impl => ifds}/JavaAnalysisApiTest.java | 12 ++-- .../{impl => ifds}/BaseAnalysisTest.kt | 4 +- .../{impl => ifds}/ConditionEvaluatorTest.kt | 14 ++--- .../analysis/{impl => ifds}/IfdsNpeTest.kt | 6 +- .../analysis/{impl => ifds}/IfdsSqlTest.kt | 14 ++--- .../analysis/{impl => ifds}/IfdsUnusedTest.kt | 6 +- .../JodaDateTimeAnalysisTest.kt | 8 +-- .../{impl => ifds}/TaintFlowFunctionsTest.kt | 28 ++++----- .../src/main/kotlin/org/jacodb/cli/main.kt | 24 ++++---- settings.gradle.kts | 3 +- 88 files changed, 490 insertions(+), 482 deletions(-) create mode 100644 jacodb-analysis/common/build.gradle.kts rename jacodb-analysis/{taint/src/main/kotlin/org/jacodb/analysis/impl => common/src/main/kotlin/org/jacodb/analysis}/custom/AbstractFlowAnalysis.kt (96%) rename jacodb-analysis/{taint/src/main/kotlin/org/jacodb/analysis/impl => common/src/main/kotlin/org/jacodb/analysis}/custom/BackwardFlowAnalysis.kt (95%) rename jacodb-analysis/{taint/src/main/kotlin/org/jacodb/analysis/impl => common/src/main/kotlin/org/jacodb/analysis}/custom/FlowAnalysis.kt (96%) rename jacodb-analysis/{taint/src/main/kotlin/org/jacodb/analysis/impl => common/src/main/kotlin/org/jacodb/analysis}/custom/FlowAnalysisImpl.kt (99%) rename jacodb-analysis/{taint/src/main/kotlin/org/jacodb/analysis/impl => common/src/main/kotlin/org/jacodb/analysis}/custom/ForwardFlowAnalysis.kt (95%) rename jacodb-analysis/{taint/src/main/kotlin/org/jacodb/analysis/impl => common/src/main/kotlin/org/jacodb/analysis}/custom/NullAssumptionAnalysis.kt (99%) rename jacodb-analysis/{taint/src/main/kotlin/org/jacodb/analysis/impl => common/src/main/kotlin/org/jacodb/analysis}/custom/ReachingDefinitionsAnalysis.kt (97%) rename jacodb-analysis/{taint => common}/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt (100%) rename jacodb-analysis/{taint => common}/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt (100%) rename jacodb-analysis/{taint => common}/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt (100%) rename jacodb-analysis/{taint/src/test/kotlin/org/jacodb/analysis/impl => common/src/test/kotlin/org/jacodb/analysis/custom}/NullabilityAssumptionAnalysisTest.kt (96%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/ChunkResolver.kt (85%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/IfdsContext.kt (76%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/actors/ChunkManager.kt (81%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/actors/IndirectionHandlerActor.kt (84%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/actors/ProjectManager.kt (75%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/actors/Runner.kt (82%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/actors/RunnerStorage.kt (87%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/actors/Worker.kt (85%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/domain/Analyzer.kt (83%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/domain/Chunk.kt (94%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/domain/Edge.kt (94%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/domain/IndirectionHandler.kt (82%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/domain/Reason.kt (97%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/domain/RunnerId.kt (94%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/domain/Vertex.kt (94%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/messages/AnalyzerMessages.kt (85%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/messages/CommonMessage.kt (94%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/messages/IndirectionMessages.kt (85%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/messages/ProjectMessages.kt (83%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/messages/RunnerMessage.kt (88%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/messages/StorageMessages.kt (82%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/result/EagerTraceGraph.kt (96%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/result/Finding.kt (89%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/result/IfdsComputationData.kt (85%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/result/Merging.kt (90%) rename jacodb-analysis/ifds/src/main/kotlin/org/jacodb/{ => analysis}/ifds/result/TraceGraph.kt (91%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/common/ChunkStrategies.kt (72%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/common/FlowFunctions.kt (88%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/common/JcAsyncIfdsFacade.kt (87%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/common/JcBaseAnalyzer.kt (80%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/common/JcChunkResolver.kt (78%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/common/JcIfdsContext.kt (81%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/common/JcIfdsFacade.kt (78%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/common/JcIndirectionHandler.kt (85%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/common/Runners.kt (89%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/config/Condition.kt (95%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/config/Position.kt (89%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/config/TaintAction.kt (90%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/npe/Builders.kt (74%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/npe/Findings.kt (84%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/npe/NpeAnalyzers.kt (83%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/npe/NpeFlowFunctions.kt (95%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/npe/Utils.kt (89%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/sarif/Sarif.kt (98%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/sarif/SourceFileResolver.kt (95%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/sarif/Vulnerability.kt (81%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/taint/Builders.kt (74%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/taint/Findings.kt (88%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/taint/TaintAnalyzers.kt (83%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/taint/TaintFacts.kt (91%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/taint/TaintFlowFunctions.kt (95%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/unused/Builders.kt (81%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/unused/Findings.kt (87%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/unused/UnusedVariableAnalyzer.kt (76%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/unused/UnusedVariableFacts.kt (91%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/unused/UnusedVariableFlowFunctions.kt (84%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/unused/Utils.kt (93%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/util/AccessPath.kt (98%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/util/Accessors.kt (96%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/util/Extensions.kt (97%) rename jacodb-analysis/taint/src/main/kotlin/org/jacodb/{ => analysis}/ifds/util/Maybe.kt (97%) rename jacodb-analysis/taint/src/test/java/org/jacodb/analysis/{impl => ifds}/JavaAnalysisApiTest.java (89%) rename jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/{impl => ifds}/BaseAnalysisTest.kt (98%) rename jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/{impl => ifds}/ConditionEvaluatorTest.kt (96%) rename jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/{impl => ifds}/IfdsNpeTest.kt (98%) rename jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/{impl => ifds}/IfdsSqlTest.kt (91%) rename jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/{impl => ifds}/IfdsUnusedTest.kt (95%) rename jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/{impl => ifds}/JodaDateTimeAnalysisTest.kt (94%) rename jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/{impl => ifds}/TaintFlowFunctionsTest.kt (88%) diff --git a/jacodb-analysis/README.md b/jacodb-analysis/README.md index cb6a4b854..132c24eac 100644 --- a/jacodb-analysis/README.md +++ b/jacodb-analysis/README.md @@ -1,3 +1,5 @@ +# OUTDATED! + # Module `jacodb-analysis` The `jacodb-analysis` module allows launching application dataflow analyses. diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 82e7086e4..4233f549f 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -19,7 +19,6 @@ package org.jacodb.actors.impl import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job -import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import mu.KLogger import mu.KotlinLogging.logger diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt index 15f7ae4a5..cf8739417 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt @@ -21,7 +21,6 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.onClosed import kotlinx.coroutines.channels.onSuccess import kotlinx.coroutines.launch -import mu.KLogger import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef diff --git a/jacodb-analysis/common/build.gradle.kts b/jacodb-analysis/common/build.gradle.kts new file mode 100644 index 000000000..60c99010f --- /dev/null +++ b/jacodb-analysis/common/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + kotlin("plugin.serialization") + `java-test-fixtures` +} + +dependencies { + api(project(":jacodb-core")) + api(project(":jacodb-api")) + + implementation(Libs.kotlin_logging) + implementation(Libs.slf4j_simple) + implementation(Libs.kotlinx_coroutines_core) + implementation(Libs.kotlinx_serialization_json) + + testImplementation(testFixtures(project(":jacodb-core"))) +} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/AbstractFlowAnalysis.kt similarity index 96% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt rename to jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/AbstractFlowAnalysis.kt index ae943f3c3..add0813c6 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/AbstractFlowAnalysis.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/AbstractFlowAnalysis.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.impl.custom +package org.jacodb.analysis.custom import org.jacodb.api.cfg.JcBytecodeGraph diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/BackwardFlowAnalysis.kt similarity index 95% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt rename to jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/BackwardFlowAnalysis.kt index 0fec7e461..05f65d457 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/BackwardFlowAnalysis.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/BackwardFlowAnalysis.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.impl.custom +package org.jacodb.analysis.custom import org.jacodb.api.cfg.JcBytecodeGraph diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/FlowAnalysis.kt similarity index 96% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt rename to jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/FlowAnalysis.kt index c2e1ae111..311e46cef 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysis.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/FlowAnalysis.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.impl.custom +package org.jacodb.analysis.custom import org.jacodb.api.cfg.JcBytecodeGraph diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/FlowAnalysisImpl.kt similarity index 99% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt rename to jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/FlowAnalysisImpl.kt index 52049a9f4..eee2782a9 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/FlowAnalysisImpl.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/FlowAnalysisImpl.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.impl.custom +package org.jacodb.analysis.custom import org.jacodb.api.cfg.JcBytecodeGraph import org.jacodb.api.cfg.JcGotoInst diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/ForwardFlowAnalysis.kt similarity index 95% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt rename to jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/ForwardFlowAnalysis.kt index 71dc1186e..0636051a4 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/ForwardFlowAnalysis.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/ForwardFlowAnalysis.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.impl.custom +package org.jacodb.analysis.custom import org.jacodb.api.cfg.JcBytecodeGraph diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/NullAssumptionAnalysis.kt similarity index 99% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt rename to jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/NullAssumptionAnalysis.kt index 610c92e2c..89ceb274b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/NullAssumptionAnalysis.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/NullAssumptionAnalysis.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.impl.custom +package org.jacodb.analysis.custom import org.jacodb.api.JcRefType import org.jacodb.api.cfg.JcArrayAccess diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/ReachingDefinitionsAnalysis.kt similarity index 97% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt rename to jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/ReachingDefinitionsAnalysis.kt index 5955d88a2..1d56e9e06 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/impl/custom/ReachingDefinitionsAnalysis.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/ReachingDefinitionsAnalysis.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.analysis.impl.custom +package org.jacodb.analysis.custom import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcBasicBlock @@ -22,8 +22,7 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.api.cfg.JcInstRef import org.jacodb.api.cfg.JcValue import org.jacodb.impl.cfg.JcBlockGraphImpl -import java.util.* -import kotlin.collections.ArrayDeque +import java.util.BitSet class ReachingDefinitionsAnalysis(val blockGraph: JcBlockGraphImpl) { val jcGraph get() = blockGraph.jcGraph diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt similarity index 100% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt rename to jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt similarity index 100% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt rename to jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/BackwardGraphs.kt diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt similarity index 100% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt rename to jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt b/jacodb-analysis/common/src/test/kotlin/org/jacodb/analysis/custom/NullabilityAssumptionAnalysisTest.kt similarity index 96% rename from jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt rename to jacodb-analysis/common/src/test/kotlin/org/jacodb/analysis/custom/NullabilityAssumptionAnalysisTest.kt index 41d4fe839..a63a8a795 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/NullabilityAssumptionAnalysisTest.kt +++ b/jacodb-analysis/common/src/test/kotlin/org/jacodb/analysis/custom/NullabilityAssumptionAnalysisTest.kt @@ -14,9 +14,8 @@ * limitations under the License. */ -package org.jacodb.analysis.impl +package org.jacodb.analysis.custom -import org.jacodb.analysis.impl.custom.NullAssumptionAnalysis import org.jacodb.api.JcClassOrInterface import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcAssignInst diff --git a/jacodb-analysis/ifds/build.gradle.kts b/jacodb-analysis/ifds/build.gradle.kts index 51110e42d..7c02cdfdf 100644 --- a/jacodb-analysis/ifds/build.gradle.kts +++ b/jacodb-analysis/ifds/build.gradle.kts @@ -3,7 +3,8 @@ dependencies { implementation(Libs.slf4j_simple) implementation(Libs.kotlinx_coroutines_core) - implementation(project(":jacodb-analysis:actors")) + api(project(":jacodb-analysis:actors")) + api(project(":jacodb-analysis:common")) testImplementation(kotlin("test")) } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkResolver.kt similarity index 85% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkResolver.kt index 05febd822..a90a58344 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/ChunkResolver.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkResolver.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.jacodb.ifds +package org.jacodb.analysis.ifds -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.domain.Chunk +import org.jacodb.analysis.ifds.messages.RunnerMessage fun interface ChunkResolver { fun chunkByMessage(message: RunnerMessage): Chunk diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt similarity index 76% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt index da5cea814..df09fc5b2 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/IfdsContext.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt @@ -14,13 +14,13 @@ * limitations under the License. */ -package org.jacodb.ifds +package org.jacodb.analysis.ifds -import org.jacodb.ifds.domain.Analyzer -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.domain.IndirectionHandler -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.domain.Analyzer +import org.jacodb.analysis.ifds.domain.Chunk +import org.jacodb.analysis.ifds.domain.IndirectionHandler +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.messages.RunnerMessage interface IfdsContext { fun chunkByMessage(message: RunnerMessage): Chunk diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt similarity index 81% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt index a115e13de..a76f2bda1 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ChunkManager.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt @@ -14,22 +14,21 @@ * limitations under the License. */ -package org.jacodb.ifds.actors +package org.jacodb.analysis.ifds.actors import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.signal.Signal import org.jacodb.actors.impl.routing.messageKeyRouter -import org.jacodb.ifds.IfdsContext -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.messages.CommonMessage -import org.jacodb.ifds.messages.NewChunk -import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.domain.Chunk +import org.jacodb.analysis.ifds.messages.CommonMessage +import org.jacodb.analysis.ifds.messages.NewChunk +import org.jacodb.analysis.ifds.messages.RunnerMessage context(ActorContext) class ChunkManager( - private val ifdsContext: IfdsContext, + private val ifdsContext: org.jacodb.analysis.ifds.IfdsContext, private val chunk: Chunk, private val parent: ActorRef, ) : Actor { @@ -37,7 +36,7 @@ class ChunkManager( private val routerFactory = messageKeyRouter( ifdsContext::runnerIdByMessage ) { runnerId -> - Runner(this@ActorContext.self, ifdsContext, chunk, runnerId) + org.jacodb.analysis.ifds.actors.Runner(this@ActorContext.self, ifdsContext, chunk, runnerId) } private val router = spawn( diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/IndirectionHandlerActor.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/IndirectionHandlerActor.kt similarity index 84% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/IndirectionHandlerActor.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/IndirectionHandlerActor.kt index c83190350..45b62a6e7 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/IndirectionHandlerActor.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/IndirectionHandlerActor.kt @@ -14,14 +14,14 @@ * limitations under the License. */ -package org.jacodb.ifds.actors +package org.jacodb.analysis.ifds.actors import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef -import org.jacodb.ifds.domain.IndirectionHandler -import org.jacodb.ifds.messages.IndirectionMessage -import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.domain.IndirectionHandler +import org.jacodb.analysis.ifds.messages.IndirectionMessage +import org.jacodb.analysis.ifds.messages.RunnerMessage context(ActorContext) class IndirectionHandlerActor( diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt similarity index 75% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt index 79ce6a38d..99d1e8dbe 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/ProjectManager.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt @@ -14,31 +14,30 @@ * limitations under the License. */ -package org.jacodb.ifds.actors +package org.jacodb.analysis.ifds.actors import kotlinx.coroutines.CompletableDeferred import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.impl.routing.messageKeyRouter -import org.jacodb.ifds.IfdsContext -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.messages.CollectAllData -import org.jacodb.ifds.messages.CommonMessage -import org.jacodb.ifds.messages.NewChunk -import org.jacodb.ifds.messages.CollectData -import org.jacodb.ifds.messages.ProjectMessage -import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.result.IfdsComputationData -import org.jacodb.ifds.result.Finding +import org.jacodb.analysis.ifds.domain.Chunk +import org.jacodb.analysis.ifds.messages.CollectAllData +import org.jacodb.analysis.ifds.messages.CollectData +import org.jacodb.analysis.ifds.messages.CommonMessage +import org.jacodb.analysis.ifds.messages.NewChunk +import org.jacodb.analysis.ifds.messages.ProjectMessage +import org.jacodb.analysis.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.result.Finding +import org.jacodb.analysis.ifds.result.IfdsComputationData context(ActorContext) class ProjectManager( - private val ifdsContext: IfdsContext, + private val ifdsContext: org.jacodb.analysis.ifds.IfdsContext, ) : Actor { private val routerFactory = messageKeyRouter( keyExtractor = ifdsContext::chunkByMessage - ) { chunk -> ChunkManager(ifdsContext, chunk, this@ActorContext.self) } + ) { chunk -> org.jacodb.analysis.ifds.actors.ChunkManager(ifdsContext, chunk, this@ActorContext.self) } private val router = spawn("chunks", actorFactory = routerFactory) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt similarity index 82% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt index 5c212c64a..0dd446163 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Runner.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt @@ -14,25 +14,24 @@ * limitations under the License. */ -package org.jacodb.ifds.actors +package org.jacodb.analysis.ifds.actors import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.actors.impl.routing.roundRobinRouter -import org.jacodb.ifds.IfdsContext -import org.jacodb.ifds.domain.Analyzer -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.IndirectionMessage -import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.messages.StorageMessage +import org.jacodb.analysis.ifds.domain.Analyzer +import org.jacodb.analysis.ifds.domain.Chunk +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.messages.AnalyzerMessage +import org.jacodb.analysis.ifds.messages.IndirectionMessage +import org.jacodb.analysis.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.messages.StorageMessage context(ActorContext) class Runner( private val parent: ActorRef, - private val ifdsContext: IfdsContext, + private val ifdsContext: org.jacodb.analysis.ifds.IfdsContext, private val chunk: Chunk, private val runnerId: RunnerId, ) : Actor { diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt similarity index 87% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt index 202650d59..2c2679135 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/RunnerStorage.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt @@ -14,29 +14,29 @@ * limitations under the License. */ -package org.jacodb.ifds.actors +package org.jacodb.analysis.ifds.actors import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.CollectData -import org.jacodb.ifds.messages.EdgeMessage -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.NewFinding -import org.jacodb.ifds.messages.NewSummaryEdge -import org.jacodb.ifds.messages.NotificationOnEnd -import org.jacodb.ifds.messages.NotificationOnStart -import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.messages.StorageMessage -import org.jacodb.ifds.messages.SubscriptionOnEnd -import org.jacodb.ifds.messages.SubscriptionOnStart -import org.jacodb.ifds.result.Finding -import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.Reason +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.domain.Vertex +import org.jacodb.analysis.ifds.messages.AnalyzerMessage +import org.jacodb.analysis.ifds.messages.CollectData +import org.jacodb.analysis.ifds.messages.EdgeMessage +import org.jacodb.analysis.ifds.messages.NewEdge +import org.jacodb.analysis.ifds.messages.NewFinding +import org.jacodb.analysis.ifds.messages.NewSummaryEdge +import org.jacodb.analysis.ifds.messages.NotificationOnEnd +import org.jacodb.analysis.ifds.messages.NotificationOnStart +import org.jacodb.analysis.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.messages.StorageMessage +import org.jacodb.analysis.ifds.messages.SubscriptionOnEnd +import org.jacodb.analysis.ifds.messages.SubscriptionOnStart +import org.jacodb.analysis.ifds.result.Finding +import org.jacodb.analysis.ifds.result.IfdsComputationData context(ActorContext) class RunnerStorage( diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Worker.kt similarity index 85% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Worker.kt index 7e8b9553a..c5b6c479e 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/actors/Worker.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Worker.kt @@ -14,14 +14,14 @@ * limitations under the License. */ -package org.jacodb.ifds.actors +package org.jacodb.analysis.ifds.actors import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef -import org.jacodb.ifds.domain.Analyzer -import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.domain.Analyzer +import org.jacodb.analysis.ifds.messages.AnalyzerMessage +import org.jacodb.analysis.ifds.messages.RunnerMessage context(ActorContext>) class Worker( diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Analyzer.kt similarity index 83% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Analyzer.kt index ba1149f63..6162c8a7d 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Analyzer.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Analyzer.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.jacodb.ifds.domain +package org.jacodb.analysis.ifds.domain -import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.messages.AnalyzerMessage +import org.jacodb.analysis.ifds.messages.RunnerMessage interface Analyzer { fun handle(message: AnalyzerMessage): Collection diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Chunk.kt similarity index 94% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Chunk.kt index b3cca8949..133d82d9b 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Chunk.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Chunk.kt @@ -14,6 +14,6 @@ * limitations under the License. */ -package org.jacodb.ifds.domain +package org.jacodb.analysis.ifds.domain interface Chunk diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Edge.kt similarity index 94% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Edge.kt index c34e7bdae..736658ff7 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Edge.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Edge.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.domain +package org.jacodb.analysis.ifds.domain data class Edge( val from: Vertex, diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/IndirectionHandler.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/IndirectionHandler.kt similarity index 82% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/IndirectionHandler.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/IndirectionHandler.kt index 8fcfceece..269741bb2 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/IndirectionHandler.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/IndirectionHandler.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.jacodb.ifds.domain +package org.jacodb.analysis.ifds.domain -import org.jacodb.ifds.messages.IndirectionMessage -import org.jacodb.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.messages.IndirectionMessage +import org.jacodb.analysis.ifds.messages.RunnerMessage interface IndirectionHandler { fun handle(message: IndirectionMessage): Collection diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Reason.kt similarity index 97% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Reason.kt index cef643608..2d46c7f6c 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Reason.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Reason.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.domain +package org.jacodb.analysis.ifds.domain sealed interface Reason { data object Initial : Reason diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/RunnerId.kt similarity index 94% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/RunnerId.kt index 7f2f19d8f..b2aac4d19 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/RunnerId.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/RunnerId.kt @@ -14,6 +14,6 @@ * limitations under the License. */ -package org.jacodb.ifds.domain +package org.jacodb.analysis.ifds.domain interface RunnerId diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Vertex.kt similarity index 94% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Vertex.kt index 1d7a5146b..63d800a51 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/domain/Vertex.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/Vertex.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.domain +package org.jacodb.analysis.ifds.domain data class Vertex( val statement: Stmt, diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/AnalyzerMessages.kt similarity index 85% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/AnalyzerMessages.kt index 694b86cb3..08cbd11d7 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/AnalyzerMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/AnalyzerMessages.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.jacodb.ifds.messages +package org.jacodb.analysis.ifds.messages -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.RunnerId interface AnalyzerMessage : RunnerMessage @@ -32,6 +32,11 @@ data class ResolvedCall( val method: Method, ) : AnalyzerMessage +data class NoResolvedCall( + override val runnerId: RunnerId, + val edge: Edge, +) : AnalyzerMessage + data class NotificationOnStart( val subscriber: RunnerId, val author: RunnerId, diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/CommonMessage.kt similarity index 94% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessage.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/CommonMessage.kt index 4b341019f..3ffcc20ae 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/CommonMessage.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/CommonMessage.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.messages +package org.jacodb.analysis.ifds.messages sealed interface CommonMessage diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/IndirectionMessages.kt similarity index 85% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/IndirectionMessages.kt index e2c445fbf..e89251ff4 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/IndirectionMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/IndirectionMessages.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.jacodb.ifds.messages +package org.jacodb.analysis.ifds.messages -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.RunnerId interface IndirectionMessage : RunnerMessage diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/ProjectMessages.kt similarity index 83% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/ProjectMessages.kt index f79fb52de..e6056fa9a 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/ProjectMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/ProjectMessages.kt @@ -14,12 +14,12 @@ * limitations under the License. */ -package org.jacodb.ifds.messages +package org.jacodb.analysis.ifds.messages import kotlinx.coroutines.CompletableDeferred -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.result.IfdsComputationData +import org.jacodb.analysis.ifds.domain.Chunk +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.result.IfdsComputationData sealed interface ProjectMessage : CommonMessage diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/RunnerMessage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/RunnerMessage.kt similarity index 88% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/RunnerMessage.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/RunnerMessage.kt index 8a095af29..0637d3dec 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/RunnerMessage.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/RunnerMessage.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.jacodb.ifds.messages +package org.jacodb.analysis.ifds.messages -import org.jacodb.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.domain.RunnerId sealed interface RunnerMessage : CommonMessage { val runnerId: RunnerId diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/StorageMessages.kt similarity index 82% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/StorageMessages.kt index 87e0a0071..80a7f785a 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/messages/StorageMessages.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/messages/StorageMessages.kt @@ -14,16 +14,16 @@ * limitations under the License. */ -package org.jacodb.ifds.messages +package org.jacodb.analysis.ifds.messages import kotlinx.coroutines.CompletableDeferred -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.result.IfdsComputationData -import org.jacodb.ifds.result.Finding +import org.jacodb.analysis.ifds.domain.Chunk +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.Reason +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.domain.Vertex +import org.jacodb.analysis.ifds.result.Finding +import org.jacodb.analysis.ifds.result.IfdsComputationData sealed interface StorageMessage : RunnerMessage diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/EagerTraceGraph.kt similarity index 96% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/EagerTraceGraph.kt index c90a16211..fc7289c23 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/EagerTraceGraph.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/EagerTraceGraph.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.jacodb.ifds.result +package org.jacodb.analysis.ifds.result -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.Vertex +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.Reason +import org.jacodb.analysis.ifds.domain.Vertex data class EagerTraceGraph( override val sink: Vertex, diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Finding.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/Finding.kt similarity index 89% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Finding.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/Finding.kt index ffb9db748..ff8355890 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Finding.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/Finding.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.jacodb.ifds.result +package org.jacodb.analysis.ifds.result -import org.jacodb.ifds.domain.Vertex +import org.jacodb.analysis.ifds.domain.Vertex interface Finding { val vertex: Vertex diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/IfdsComputationData.kt similarity index 85% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/IfdsComputationData.kt index 903c3efd0..97dd84632 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/IfdsComputationData.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/IfdsComputationData.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.jacodb.ifds.result +package org.jacodb.analysis.ifds.result -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.Vertex +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.Reason +import org.jacodb.analysis.ifds.domain.Vertex /** * Aggregates all facts and edges found by the tabulation algorithm. diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/Merging.kt similarity index 90% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/Merging.kt index 871480ce2..3cf104689 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/Merging.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/Merging.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.jacodb.ifds.result +package org.jacodb.analysis.ifds.result -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.Vertex +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.Reason +import org.jacodb.analysis.ifds.domain.Vertex fun > mergeIfdsResults( ifdsResults: Collection>, diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/TraceGraph.kt similarity index 91% rename from jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/TraceGraph.kt index c9572ac50..d8e947d11 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/ifds/result/TraceGraph.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/result/TraceGraph.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.jacodb.ifds.result +package org.jacodb.analysis.ifds.result -import org.jacodb.ifds.domain.Vertex +import org.jacodb.analysis.ifds.domain.Vertex interface TraceGraph { val sink: Vertex diff --git a/jacodb-analysis/taint/build.gradle.kts b/jacodb-analysis/taint/build.gradle.kts index 54cc7282e..3d62f17cc 100644 --- a/jacodb-analysis/taint/build.gradle.kts +++ b/jacodb-analysis/taint/build.gradle.kts @@ -8,7 +8,6 @@ dependencies { api(project(":jacodb-api")) api(project(":jacodb-taint-configuration")) - api(project(":jacodb-analysis:actors")) api(project(":jacodb-analysis:ifds")) implementation(Libs.kotlin_logging) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/ChunkStrategies.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/ChunkStrategies.kt similarity index 72% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/ChunkStrategies.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/ChunkStrategies.kt index 0b4d27b5b..d4f656d27 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/ChunkStrategies.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/ChunkStrategies.kt @@ -14,18 +14,17 @@ * limitations under the License. */ -package org.jacodb.ifds.common +package org.jacodb.analysis.ifds.common +import org.jacodb.analysis.ifds.domain.Chunk import org.jacodb.api.JcClassOrInterface import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.packageName -import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.domain.Chunk data object SingletonChunk : Chunk -val SingletonChunkStrategy = ChunkStrategy { +val SingletonChunkStrategy = org.jacodb.analysis.ifds.ChunkStrategy { SingletonChunk } @@ -33,7 +32,7 @@ data class MethodChunk( val method: JcMethod, ) : Chunk -val MethodChunkStrategy = ChunkStrategy { stmt -> +val MethodChunkStrategy = org.jacodb.analysis.ifds.ChunkStrategy { stmt -> MethodChunk(stmt.location.method) } @@ -41,12 +40,12 @@ data class ClassChunk( val jcClass: JcClassOrInterface, ) : Chunk -val ClassChunkStrategy = ChunkStrategy { stmt -> +val ClassChunkStrategy = org.jacodb.analysis.ifds.ChunkStrategy { stmt -> val jcClass = stmt.location.method.enclosingClass ClassChunk(jcClass) } -val ClassWithNestedChunkStrategy = ChunkStrategy { stmt -> +val ClassWithNestedChunkStrategy = org.jacodb.analysis.ifds.ChunkStrategy { stmt -> val jClass = generateSequence(stmt.location.method.enclosingClass) { it.outerClass } .last() ClassChunk(jClass) @@ -56,6 +55,6 @@ data class PackageChunk( val packageName: String, ) : Chunk -val PackageChunkStrategy = ChunkStrategy { stmt -> +val PackageChunkStrategy = org.jacodb.analysis.ifds.ChunkStrategy { stmt -> PackageChunk(stmt.location.method.enclosingClass.packageName) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/FlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/FlowFunctions.kt similarity index 88% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/FlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/FlowFunctions.kt index f1145b773..e4b445681 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/FlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/FlowFunctions.kt @@ -14,9 +14,15 @@ * limitations under the License. */ -package org.jacodb.ifds.common +package org.jacodb.analysis.ifds.common + +interface FlowFunctions { + /** + * Method for obtaining initial domain facts at the method entrypoint. + * Commonly, it is only `listOf(Zero)`. + */ + fun obtainPossibleStartFacts(method: Method): Collection -interface FlowFunctions { /** * Sequent flow function. * diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcAsyncIfdsFacade.kt similarity index 87% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcAsyncIfdsFacade.kt index 5c3fd80a4..9bfbff5b5 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcAsyncIfdsFacade.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcAsyncIfdsFacade.kt @@ -14,20 +14,20 @@ * limitations under the License. */ -package org.jacodb.ifds.common +package org.jacodb.analysis.ifds.common import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.future.future +import org.jacodb.analysis.ifds.result.Finding import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.result.Finding import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds class JcAsyncIfdsFacade>( - private val ifdsFacade: JcIfdsFacade -) { + private val ifdsFacade: JcIfdsFacade, +) : AutoCloseable { private val scope = CoroutineScope(Job()) @JvmName("runAnalysis") @@ -55,4 +55,8 @@ class JcAsyncIfdsFacade>( fun collectComputationData() = scope.future { ifdsFacade.collectComputationData() } + + override fun close() { + ifdsFacade.close() + } } \ No newline at end of file diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt similarity index 80% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt index 29ca08b56..e7420ed5f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcBaseAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt @@ -14,31 +14,32 @@ * limitations under the License. */ -package org.jacodb.ifds.common - +package org.jacodb.analysis.ifds.common + +import org.jacodb.analysis.ifds.domain.Analyzer +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.Reason +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.domain.Vertex +import org.jacodb.analysis.ifds.messages.AnalyzerMessage +import org.jacodb.analysis.ifds.messages.EdgeMessage +import org.jacodb.analysis.ifds.messages.NewEdge +import org.jacodb.analysis.ifds.messages.NoResolvedCall +import org.jacodb.analysis.ifds.messages.NotificationOnStart +import org.jacodb.analysis.ifds.messages.ResolvedCall +import org.jacodb.analysis.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.messages.SubscriptionOnStart +import org.jacodb.analysis.ifds.messages.UnresolvedCall import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr -import org.jacodb.ifds.domain.Analyzer -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.EdgeMessage -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.NotificationOnStart -import org.jacodb.ifds.messages.ResolvedCall -import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.messages.SubscriptionOnStart -import org.jacodb.ifds.messages.UnresolvedCall abstract class JcBaseAnalyzer( protected val selfRunnerId: RunnerId, protected val graph: JcApplicationGraph, ) : Analyzer { - abstract val flowFunctions: FlowFunctions + abstract val flowFunctions: FlowFunctions override fun handle(message: AnalyzerMessage): Collection = buildList { when (message) { @@ -55,6 +56,12 @@ abstract class JcBaseAnalyzer( ) } + is NoResolvedCall -> { + processNoResolvedCall( + message.edge + ) + } + is NotificationOnStart -> { processNotificationOnStart(message.subscribingEdge, message.summaryEdge) } @@ -65,17 +72,6 @@ abstract class JcBaseAnalyzer( } } - private fun MutableList.processStartAnalysis(method: JcMethod) { - for (fact in obtainPossibleStartFacts(method)) { - for (entryPoint in graph.entryPoints(method)) { - val vertex = Vertex(entryPoint, fact) - val edge = Edge(vertex, vertex) - val newEdgeMessage = NewEdge(selfRunnerId, edge, Reason.Initial) - add(newEdgeMessage) - } - } - } - private fun MutableList.processEdge(edge: Edge) { val toStmt = edge.to.statement val method = graph.methodOf(toStmt) @@ -151,6 +147,9 @@ abstract class JcBaseAnalyzer( } } + private fun processNoResolvedCall(edge: Edge) { + TODO("Not yet implemented") + } private fun MutableList.processNotificationOnStart( callerEdge: Edge, @@ -186,10 +185,4 @@ abstract class JcBaseAnalyzer( } protected abstract fun MutableList.onNewEdge(newEdge: Edge) - - /** - * Method for obtaining initial domain facts at the method entrypoint. - * Commonly, it is only `listOf(Zero)`. - */ - abstract fun obtainPossibleStartFacts(method: JcMethod): Collection } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt similarity index 78% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt index 8185e63d5..a456d4556 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcChunkResolver.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt @@ -14,33 +14,31 @@ * limitations under the License. */ -package org.jacodb.ifds.common +package org.jacodb.analysis.ifds.common +import org.jacodb.analysis.ifds.domain.Chunk +import org.jacodb.analysis.ifds.messages.AnalyzerMessage +import org.jacodb.analysis.ifds.messages.CollectData +import org.jacodb.analysis.ifds.messages.EdgeMessage +import org.jacodb.analysis.ifds.messages.IndirectionMessage +import org.jacodb.analysis.ifds.messages.NewEdge +import org.jacodb.analysis.ifds.messages.NewFinding +import org.jacodb.analysis.ifds.messages.NewSummaryEdge +import org.jacodb.analysis.ifds.messages.NotificationOnEnd +import org.jacodb.analysis.ifds.messages.NotificationOnStart +import org.jacodb.analysis.ifds.messages.ResolvedCall +import org.jacodb.analysis.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.messages.StorageMessage +import org.jacodb.analysis.ifds.messages.SubscriptionOnEnd +import org.jacodb.analysis.ifds.messages.SubscriptionOnStart +import org.jacodb.analysis.ifds.messages.UnresolvedCall import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkResolver -import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.messages.AnalyzerMessage -import org.jacodb.ifds.messages.CollectData -import org.jacodb.ifds.messages.EdgeMessage -import org.jacodb.ifds.messages.IndirectionMessage -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.messages.NewFinding -import org.jacodb.ifds.messages.NewSummaryEdge -import org.jacodb.ifds.messages.NotificationOnEnd -import org.jacodb.ifds.messages.NotificationOnStart -import org.jacodb.ifds.messages.ResolvedCall -import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.messages.StorageMessage -import org.jacodb.ifds.messages.SubscriptionOnEnd -import org.jacodb.ifds.messages.SubscriptionOnStart -import org.jacodb.ifds.messages.UnresolvedCall class JcChunkResolver( private val graph: JcApplicationGraph, - private val chunkStrategy: ChunkStrategy, -) : ChunkResolver { + private val chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy, +) : org.jacodb.analysis.ifds.ChunkResolver { @Suppress("UNCHECKED_CAST") override fun chunkByMessage(message: RunnerMessage): Chunk = when (message) { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt similarity index 81% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt index ad1177cd8..0c136af6b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsContext.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt @@ -14,25 +14,23 @@ * limitations under the License. */ -package org.jacodb.ifds.common +package org.jacodb.analysis.ifds.common +import org.jacodb.analysis.ifds.domain.Chunk +import org.jacodb.analysis.ifds.domain.IndirectionHandler +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.messages.RunnerMessage import org.jacodb.api.JcClasspath import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkResolver -import org.jacodb.ifds.IfdsContext -import org.jacodb.ifds.domain.Chunk -import org.jacodb.ifds.domain.IndirectionHandler -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.impl.features.HierarchyExtensionImpl import java.util.concurrent.ConcurrentHashMap class JcIfdsContext( private val cp: JcClasspath, private val bannedPackagePrefixes: List, - private val chunkStrategy: ChunkResolver, + private val chunkStrategy: org.jacodb.analysis.ifds.ChunkResolver, private val analyzerFactory: (RunnerId) -> JcBaseAnalyzer, -) : IfdsContext { +) : org.jacodb.analysis.ifds.IfdsContext { override fun chunkByMessage(message: RunnerMessage): Chunk = chunkStrategy.chunkByMessage(message) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt similarity index 78% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt index 768f20c1c..b63f188ee 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIfdsFacade.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt @@ -14,25 +14,25 @@ * limitations under the License. */ -package org.jacodb.ifds.common +package org.jacodb.analysis.ifds.common import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.jacodb.actors.api.ActorSystem +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.Reason +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.domain.Vertex +import org.jacodb.analysis.ifds.messages.CollectAllData +import org.jacodb.analysis.ifds.messages.CommonMessage +import org.jacodb.analysis.ifds.messages.NewEdge +import org.jacodb.analysis.ifds.result.Finding +import org.jacodb.analysis.ifds.result.IfdsComputationData +import org.jacodb.analysis.ifds.result.mergeIfdsResults import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.Reason -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.messages.CollectAllData -import org.jacodb.ifds.messages.CommonMessage -import org.jacodb.ifds.messages.NewEdge -import org.jacodb.ifds.result.Finding -import org.jacodb.ifds.result.IfdsComputationData -import org.jacodb.ifds.result.mergeIfdsResults import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds @@ -41,7 +41,7 @@ open class JcIfdsFacade>( private val context: JcIfdsContext, private val system: ActorSystem, private val startingRunnerId: RunnerId, -) { +) : AutoCloseable { open suspend fun runAnalysis( methods: Collection, timeout: Duration = 60.seconds, @@ -63,7 +63,7 @@ open class JcIfdsFacade>( method: JcMethod, ) { val analyzer = context.getAnalyzer(startingRunnerId) - for (fact in analyzer.obtainPossibleStartFacts(method)) { + for (fact in analyzer.flowFunctions.obtainPossibleStartFacts(method)) { for (entryPoint in graph.entryPoints(method)) { val vertex = Vertex(entryPoint, fact) val edge = Edge(vertex, vertex) @@ -88,4 +88,8 @@ open class JcIfdsFacade>( return mergeIfdsResults(ifdsData) } -} \ No newline at end of file + + override fun close() { + system.close() + } +} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt similarity index 85% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt index 42ecb905e..9910ecbf5 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/JcIndirectionHandler.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt @@ -14,8 +14,15 @@ * limitations under the License. */ -package org.jacodb.ifds.common +package org.jacodb.analysis.ifds.common +import org.jacodb.analysis.ifds.domain.IndirectionHandler +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.messages.IndirectionMessage +import org.jacodb.analysis.ifds.messages.ResolvedCall +import org.jacodb.analysis.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.messages.UnresolvedCall +import org.jacodb.analysis.ifds.taint.TaintDomainFact import org.jacodb.api.JcClassType import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst @@ -23,13 +30,6 @@ import org.jacodb.api.cfg.JcVirtualCallExpr import org.jacodb.api.ext.HierarchyExtension import org.jacodb.api.ext.cfg.callExpr import org.jacodb.api.ext.isSubClassOf -import org.jacodb.ifds.domain.IndirectionHandler -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.IndirectionMessage -import org.jacodb.ifds.messages.ResolvedCall -import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.messages.UnresolvedCall -import org.jacodb.ifds.taint.TaintDomainFact class JcIndirectionHandler( private val hierarchy: HierarchyExtension, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/Runners.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/Runners.kt similarity index 89% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/Runners.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/Runners.kt index ed26da7b3..019f83c7c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/common/Runners.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/Runners.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.jacodb.ifds.common +package org.jacodb.analysis.ifds.common -import org.jacodb.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.domain.RunnerId data object SingletonRunnerId : RunnerId diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/config/Condition.kt similarity index 95% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/config/Condition.kt index efd0d3d94..7da560d41 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Condition.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/config/Condition.kt @@ -14,20 +14,20 @@ * limitations under the License. */ -package org.jacodb.ifds.config - +package org.jacodb.analysis.ifds.config + +import org.jacodb.analysis.ifds.taint.Tainted +import org.jacodb.analysis.ifds.util.AccessPath +import org.jacodb.analysis.ifds.util.ElementAccessor +import org.jacodb.analysis.ifds.util.Maybe +import org.jacodb.analysis.ifds.util.onSome +import org.jacodb.analysis.ifds.util.toPath import org.jacodb.api.cfg.JcBool import org.jacodb.api.cfg.JcConstant import org.jacodb.api.cfg.JcInt import org.jacodb.api.cfg.JcStringConstant import org.jacodb.api.cfg.JcValue import org.jacodb.api.ext.isAssignable -import org.jacodb.ifds.taint.Tainted -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.ElementAccessor -import org.jacodb.ifds.util.Maybe -import org.jacodb.ifds.util.onSome -import org.jacodb.ifds.util.toPath import org.jacodb.taint.configuration.And import org.jacodb.taint.configuration.AnnotationType import org.jacodb.taint.configuration.ConditionVisitor diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/config/Position.kt similarity index 89% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/config/Position.kt index de14f0ea5..6f19c4daa 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/Position.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/config/Position.kt @@ -14,8 +14,16 @@ * limitations under the License. */ -package org.jacodb.ifds.config +package org.jacodb.analysis.ifds.config +import org.jacodb.analysis.ifds.util.AccessPath +import org.jacodb.analysis.ifds.util.ElementAccessor +import org.jacodb.analysis.ifds.util.Maybe +import org.jacodb.analysis.ifds.util.fmap +import org.jacodb.analysis.ifds.util.getArgument +import org.jacodb.analysis.ifds.util.thisInstance +import org.jacodb.analysis.ifds.util.toMaybe +import org.jacodb.analysis.ifds.util.toPathOrNull import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcAssignInst @@ -23,14 +31,6 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.api.cfg.JcInstanceCallExpr import org.jacodb.api.cfg.JcValue import org.jacodb.api.ext.cfg.callExpr -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.ElementAccessor -import org.jacodb.ifds.util.Maybe -import org.jacodb.ifds.util.fmap -import org.jacodb.ifds.util.getArgument -import org.jacodb.ifds.util.thisInstance -import org.jacodb.ifds.util.toMaybe -import org.jacodb.ifds.util.toPathOrNull import org.jacodb.taint.configuration.AnyArgument import org.jacodb.taint.configuration.Argument import org.jacodb.taint.configuration.Position diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/config/TaintAction.kt similarity index 90% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/config/TaintAction.kt index 34b36c099..05d780e0a 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/config/TaintAction.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/config/TaintAction.kt @@ -14,13 +14,13 @@ * limitations under the License. */ -package org.jacodb.ifds.config +package org.jacodb.analysis.ifds.config -import org.jacodb.ifds.taint.Tainted -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.Maybe -import org.jacodb.ifds.util.fmap -import org.jacodb.ifds.util.map +import org.jacodb.analysis.ifds.taint.Tainted +import org.jacodb.analysis.ifds.util.AccessPath +import org.jacodb.analysis.ifds.util.Maybe +import org.jacodb.analysis.ifds.util.fmap +import org.jacodb.analysis.ifds.util.map import org.jacodb.taint.configuration.AssignMark import org.jacodb.taint.configuration.CopyAllMarks import org.jacodb.taint.configuration.CopyMark diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt similarity index 74% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt index 2c95da80b..575e2f409 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt @@ -14,28 +14,27 @@ * limitations under the License. */ -package org.jacodb.ifds.npe +package org.jacodb.analysis.ifds.npe import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.ifds.actors.ProjectManager +import org.jacodb.analysis.ifds.common.ClassChunkStrategy +import org.jacodb.analysis.ifds.common.JcAsyncIfdsFacade +import org.jacodb.analysis.ifds.common.JcChunkResolver +import org.jacodb.analysis.ifds.common.JcIfdsContext +import org.jacodb.analysis.ifds.common.JcIfdsFacade +import org.jacodb.analysis.ifds.common.SingletonRunnerId +import org.jacodb.analysis.ifds.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.actors.ProjectManager -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.common.JcAsyncIfdsFacade -import org.jacodb.ifds.common.JcChunkResolver -import org.jacodb.ifds.common.JcIfdsContext -import org.jacodb.ifds.common.JcIfdsFacade -import org.jacodb.ifds.common.SingletonRunnerId -import org.jacodb.ifds.taint.TaintDomainFact fun npeIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, + chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, ): JcIfdsContext = JcIfdsContext( cp, @@ -55,7 +54,7 @@ fun npeIfdsFacade( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, + chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, ): JcIfdsFacade { val context = npeIfdsContext(cp, graph, bannedPackagePrefixes, chunkStrategy) val system = system(name) { ProjectManager(context) } @@ -67,7 +66,7 @@ fun asyncNpeIfdsFacade( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, + chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, ): JcAsyncIfdsFacade { val facade = npeIfdsFacade(name, cp, graph, bannedPackagePrefixes, chunkStrategy) return JcAsyncIfdsFacade(facade) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Findings.kt similarity index 84% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Findings.kt index 532942648..562cbcc18 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Findings.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Findings.kt @@ -14,12 +14,12 @@ * limitations under the License. */ -package org.jacodb.ifds.npe +package org.jacodb.analysis.ifds.npe +import org.jacodb.analysis.ifds.domain.Vertex +import org.jacodb.analysis.ifds.result.Finding +import org.jacodb.analysis.ifds.taint.TaintDomainFact import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.result.Finding -import org.jacodb.ifds.taint.TaintDomainFact import org.jacodb.taint.configuration.TaintMethodSink data class NpeVulnerability( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt similarity index 83% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeAnalyzers.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt index 18f8591f7..d1f17ccff 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt @@ -14,21 +14,21 @@ * limitations under the License. */ -package org.jacodb.ifds.npe - -import org.jacodb.api.JcMethod +package org.jacodb.analysis.ifds.npe + +import org.jacodb.analysis.ifds.common.JcBaseAnalyzer +import org.jacodb.analysis.ifds.config.CallPositionToJcValueResolver +import org.jacodb.analysis.ifds.config.FactAwareConditionEvaluator +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.messages.NewFinding +import org.jacodb.analysis.ifds.messages.NewSummaryEdge +import org.jacodb.analysis.ifds.messages.RunnerMessage +import org.jacodb.analysis.ifds.taint.TaintDomainFact +import org.jacodb.analysis.ifds.taint.Tainted import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr -import org.jacodb.ifds.common.JcBaseAnalyzer -import org.jacodb.ifds.config.CallPositionToJcValueResolver -import org.jacodb.ifds.config.FactAwareConditionEvaluator -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.NewFinding -import org.jacodb.ifds.messages.RunnerMessage -import org.jacodb.ifds.taint.TaintDomainFact -import org.jacodb.ifds.taint.Tainted import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.taint.configuration.TaintMark import org.jacodb.taint.configuration.TaintMethodSink @@ -56,16 +56,13 @@ class NpeAnalyzer( ForwardNpeFlowFunctions(cp, graph, taintConfigurationFeature) } - override fun obtainPossibleStartFacts(method: JcMethod): Collection = - flowFunctions.obtainPossibleStartFacts(method) - private fun isExitPoint(statement: JcInst): Boolean { return statement in graph.exitPoints(statement.location.method) } override fun MutableList.onNewEdge(newEdge: Edge) { if (isExitPoint(newEdge.to.statement)) { - add(org.jacodb.ifds.messages.NewSummaryEdge(selfRunnerId, newEdge)) + add(NewSummaryEdge(selfRunnerId, newEdge)) } val fact = newEdge.to.fact diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt similarity index 95% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt index 00291ce07..b9d57b1b7 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/NpeFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt @@ -14,8 +14,27 @@ * limitations under the License. */ -package org.jacodb.ifds.npe - +package org.jacodb.analysis.ifds.npe + +import org.jacodb.analysis.ifds.common.FlowFunctions +import org.jacodb.analysis.ifds.config.BasicConditionEvaluator +import org.jacodb.analysis.ifds.config.CallPositionToAccessPathResolver +import org.jacodb.analysis.ifds.config.CallPositionToJcValueResolver +import org.jacodb.analysis.ifds.config.EntryPointPositionToAccessPathResolver +import org.jacodb.analysis.ifds.config.EntryPointPositionToJcValueResolver +import org.jacodb.analysis.ifds.config.FactAwareConditionEvaluator +import org.jacodb.analysis.ifds.config.TaintActionEvaluator +import org.jacodb.analysis.ifds.taint.TaintDomainFact +import org.jacodb.analysis.ifds.taint.TaintZeroFact +import org.jacodb.analysis.ifds.taint.Tainted +import org.jacodb.analysis.ifds.util.AccessPath +import org.jacodb.analysis.ifds.util.ElementAccessor +import org.jacodb.analysis.ifds.util.getArgumentsOf +import org.jacodb.analysis.ifds.util.onSome +import org.jacodb.analysis.ifds.util.startsWith +import org.jacodb.analysis.ifds.util.thisInstance +import org.jacodb.analysis.ifds.util.toPath +import org.jacodb.analysis.ifds.util.toPathOrNull import org.jacodb.api.JcArrayType import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod @@ -38,25 +57,6 @@ import org.jacodb.api.cfg.JcValue import org.jacodb.api.ext.cfg.callExpr import org.jacodb.api.ext.findTypeOrNull import org.jacodb.api.ext.isNullable -import org.jacodb.ifds.common.FlowFunctions -import org.jacodb.ifds.config.BasicConditionEvaluator -import org.jacodb.ifds.config.CallPositionToAccessPathResolver -import org.jacodb.ifds.config.CallPositionToJcValueResolver -import org.jacodb.ifds.config.EntryPointPositionToAccessPathResolver -import org.jacodb.ifds.config.EntryPointPositionToJcValueResolver -import org.jacodb.ifds.config.FactAwareConditionEvaluator -import org.jacodb.ifds.config.TaintActionEvaluator -import org.jacodb.ifds.taint.TaintDomainFact -import org.jacodb.ifds.taint.TaintZeroFact -import org.jacodb.ifds.taint.Tainted -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.ElementAccessor -import org.jacodb.ifds.util.getArgumentsOf -import org.jacodb.ifds.util.onSome -import org.jacodb.ifds.util.startsWith -import org.jacodb.ifds.util.thisInstance -import org.jacodb.ifds.util.toPath -import org.jacodb.ifds.util.toPathOrNull import org.jacodb.taint.configuration.AssignMark import org.jacodb.taint.configuration.CopyAllMarks import org.jacodb.taint.configuration.CopyMark @@ -75,8 +75,8 @@ class ForwardNpeFlowFunctions( private val cp: JcClasspath, private val graph: JcApplicationGraph, private val taintConfigurationFeature: TaintConfigurationFeature?, -) : FlowFunctions { - fun obtainPossibleStartFacts( +) : FlowFunctions { + override fun obtainPossibleStartFacts( method: JcMethod, ): Collection = buildSet { addAll(obtainPossibleStartFactsBasic(method)) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Utils.kt similarity index 89% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Utils.kt index 31283d701..3bead64fc 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/npe/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Utils.kt @@ -14,16 +14,16 @@ * limitations under the License. */ -package org.jacodb.ifds.npe +package org.jacodb.analysis.ifds.npe +import org.jacodb.analysis.ifds.util.AccessPath +import org.jacodb.analysis.ifds.util.startsWith +import org.jacodb.analysis.ifds.util.toPathOrNull import org.jacodb.api.cfg.JcExpr import org.jacodb.api.cfg.JcInst import org.jacodb.api.cfg.JcInstanceCallExpr import org.jacodb.api.cfg.JcLengthExpr import org.jacodb.api.cfg.values -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.startsWith -import org.jacodb.ifds.util.toPathOrNull fun AccessPath?.isDereferencedAt(expr: JcExpr): Boolean { if (this == null) { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/sarif/Sarif.kt similarity index 98% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/sarif/Sarif.kt index 82e1acd5d..adc64524f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Sarif.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/sarif/Sarif.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.sarif +package org.jacodb.analysis.ifds.sarif import io.github.detekt.sarif4k.ArtifactLocation import io.github.detekt.sarif4k.CodeFlow @@ -32,9 +32,9 @@ import io.github.detekt.sarif4k.ThreadFlowLocation import io.github.detekt.sarif4k.Tool import io.github.detekt.sarif4k.ToolComponent import io.github.detekt.sarif4k.Version +import org.jacodb.analysis.ifds.domain.Vertex import org.jacodb.api.JcMethod import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Vertex import java.io.File private const val SARIF_SCHEMA = diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/sarif/SourceFileResolver.kt similarity index 95% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/sarif/SourceFileResolver.kt index b9c3e4007..2ee91448e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/SourceFileResolver.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/sarif/SourceFileResolver.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.sarif +package org.jacodb.analysis.ifds.sarif import org.jacodb.api.cfg.JcInst diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/sarif/Vulnerability.kt similarity index 81% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/sarif/Vulnerability.kt index a2c4e60b2..461b421a0 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/sarif/Vulnerability.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/sarif/Vulnerability.kt @@ -14,17 +14,17 @@ * limitations under the License. */ -package org.jacodb.ifds.sarif +package org.jacodb.analysis.ifds.sarif import io.github.detekt.sarif4k.Level +import org.jacodb.analysis.ifds.npe.NpeVulnerability +import org.jacodb.analysis.ifds.result.EagerTraceGraph +import org.jacodb.analysis.ifds.result.TraceGraph +import org.jacodb.analysis.ifds.taint.TaintDomainFact +import org.jacodb.analysis.ifds.taint.TaintVulnerability +import org.jacodb.analysis.ifds.unused.UnusedVariableDomainFact +import org.jacodb.analysis.ifds.unused.UnusedVulnerability import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.npe.NpeVulnerability -import org.jacodb.ifds.result.EagerTraceGraph -import org.jacodb.ifds.result.TraceGraph -import org.jacodb.ifds.taint.TaintDomainFact -import org.jacodb.ifds.taint.TaintVulnerability -import org.jacodb.ifds.unused.UnusedVariableDomainFact -import org.jacodb.ifds.unused.UnusedVulnerability data class VulnerabilityInstance( val traceGraph: TraceGraph, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt similarity index 74% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt index 00736bf11..345dcbb8e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt @@ -14,28 +14,27 @@ * limitations under the License. */ -package org.jacodb.ifds.taint +package org.jacodb.analysis.ifds.taint import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.ifds.actors.ProjectManager +import org.jacodb.analysis.ifds.common.BackwardRunnerId +import org.jacodb.analysis.ifds.common.ClassChunkStrategy +import org.jacodb.analysis.ifds.common.ForwardRunnerId +import org.jacodb.analysis.ifds.common.JcAsyncIfdsFacade +import org.jacodb.analysis.ifds.common.JcChunkResolver +import org.jacodb.analysis.ifds.common.JcIfdsContext +import org.jacodb.analysis.ifds.common.JcIfdsFacade import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.actors.ProjectManager -import org.jacodb.ifds.common.BackwardRunnerId -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.common.ForwardRunnerId -import org.jacodb.ifds.common.JcAsyncIfdsFacade -import org.jacodb.ifds.common.JcChunkResolver -import org.jacodb.ifds.common.JcIfdsContext -import org.jacodb.ifds.common.JcIfdsFacade fun taintIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, + chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, ): JcIfdsContext = JcIfdsContext( cp, @@ -54,7 +53,7 @@ fun taintIfdsFacade( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, + chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, ): JcIfdsFacade { val context = taintIfdsContext(cp, graph, bannedPackagePrefixes, chunkStrategy) val system = system(name) { ProjectManager(context) } @@ -66,7 +65,7 @@ fun asyncTaintIfdsFacade( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, + chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, ): JcAsyncIfdsFacade { val facade = taintIfdsFacade(name, cp, graph, bannedPackagePrefixes, chunkStrategy) return JcAsyncIfdsFacade(facade) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Findings.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Findings.kt similarity index 88% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Findings.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Findings.kt index ac308b724..734ab714c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/Findings.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Findings.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.jacodb.ifds.taint +package org.jacodb.analysis.ifds.taint +import org.jacodb.analysis.ifds.domain.Vertex +import org.jacodb.analysis.ifds.result.Finding import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.result.Finding import org.jacodb.taint.configuration.TaintMethodSink data class TaintVulnerability( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt similarity index 83% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzers.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt index 510d46af8..e413110e8 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt @@ -14,20 +14,19 @@ * limitations under the License. */ -package org.jacodb.ifds.taint +package org.jacodb.analysis.ifds.taint -import org.jacodb.api.JcMethod +import org.jacodb.analysis.ifds.common.JcBaseAnalyzer +import org.jacodb.analysis.ifds.config.CallPositionToJcValueResolver +import org.jacodb.analysis.ifds.config.FactAwareConditionEvaluator +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.messages.NewFinding +import org.jacodb.analysis.ifds.messages.NewSummaryEdge +import org.jacodb.analysis.ifds.messages.RunnerMessage import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst import org.jacodb.api.ext.cfg.callExpr -import org.jacodb.ifds.common.JcBaseAnalyzer -import org.jacodb.ifds.config.CallPositionToJcValueResolver -import org.jacodb.ifds.config.FactAwareConditionEvaluator -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.NewFinding -import org.jacodb.ifds.messages.NewSummaryEdge -import org.jacodb.ifds.messages.RunnerMessage import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.taint.configuration.TaintMethodSink @@ -54,10 +53,6 @@ class ForwardTaintAnalyzer( return statement in graph.exitPoints(statement.location.method) } - override fun obtainPossibleStartFacts( - method: JcMethod, - ): Collection = flowFunctions.obtainPossibleStartFacts(method) - override fun MutableList.onNewEdge(newEdge: Edge) { if (isExitPoint(newEdge.to.statement)) { add(NewSummaryEdge(selfRunnerId, newEdge)) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFacts.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFacts.kt similarity index 91% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFacts.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFacts.kt index 16b22de89..f15d5a83d 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFacts.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFacts.kt @@ -14,9 +14,9 @@ * limitations under the License. */ -package org.jacodb.ifds.taint +package org.jacodb.analysis.ifds.taint -import org.jacodb.ifds.util.AccessPath +import org.jacodb.analysis.ifds.util.AccessPath import org.jacodb.taint.configuration.TaintMark sealed interface TaintDomainFact diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt similarity index 95% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt index 08b9fda5c..9fe5751cf 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/taint/TaintFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt @@ -14,8 +14,23 @@ * limitations under the License. */ -package org.jacodb.ifds.taint - +package org.jacodb.analysis.ifds.taint + +import org.jacodb.analysis.ifds.common.FlowFunctions +import org.jacodb.analysis.ifds.config.BasicConditionEvaluator +import org.jacodb.analysis.ifds.config.CallPositionToAccessPathResolver +import org.jacodb.analysis.ifds.config.CallPositionToJcValueResolver +import org.jacodb.analysis.ifds.config.EntryPointPositionToAccessPathResolver +import org.jacodb.analysis.ifds.config.EntryPointPositionToJcValueResolver +import org.jacodb.analysis.ifds.config.FactAwareConditionEvaluator +import org.jacodb.analysis.ifds.config.TaintActionEvaluator +import org.jacodb.analysis.ifds.util.ElementAccessor +import org.jacodb.analysis.ifds.util.getArgumentsOf +import org.jacodb.analysis.ifds.util.onSome +import org.jacodb.analysis.ifds.util.startsWith +import org.jacodb.analysis.ifds.util.thisInstance +import org.jacodb.analysis.ifds.util.toPath +import org.jacodb.analysis.ifds.util.toPathOrNull import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph @@ -29,21 +44,6 @@ import org.jacodb.api.cfg.JcReturnInst import org.jacodb.api.cfg.JcThis import org.jacodb.api.cfg.JcValue import org.jacodb.api.ext.cfg.callExpr -import org.jacodb.ifds.common.FlowFunctions -import org.jacodb.ifds.config.BasicConditionEvaluator -import org.jacodb.ifds.config.CallPositionToAccessPathResolver -import org.jacodb.ifds.config.CallPositionToJcValueResolver -import org.jacodb.ifds.config.EntryPointPositionToAccessPathResolver -import org.jacodb.ifds.config.EntryPointPositionToJcValueResolver -import org.jacodb.ifds.config.FactAwareConditionEvaluator -import org.jacodb.ifds.config.TaintActionEvaluator -import org.jacodb.ifds.util.ElementAccessor -import org.jacodb.ifds.util.getArgumentsOf -import org.jacodb.ifds.util.onSome -import org.jacodb.ifds.util.startsWith -import org.jacodb.ifds.util.thisInstance -import org.jacodb.ifds.util.toPath -import org.jacodb.ifds.util.toPathOrNull import org.jacodb.taint.configuration.AssignMark import org.jacodb.taint.configuration.CopyAllMarks import org.jacodb.taint.configuration.CopyMark @@ -61,9 +61,9 @@ class ForwardTaintFlowFunctions( private val cp: JcClasspath, private val graph: JcApplicationGraph, private val taintConfigurationFeature: TaintConfigurationFeature?, -) : FlowFunctions { +) : FlowFunctions { - fun obtainPossibleStartFacts( + override fun obtainPossibleStartFacts( method: JcMethod, ): Collection = buildSet { // Zero (reachability) fact always present at entrypoint: @@ -435,8 +435,8 @@ class ForwardTaintFlowFunctions( class BackwardTaintFlowFunctions( private val project: JcClasspath, private val graph: JcApplicationGraph, -) : FlowFunctions { - fun obtainPossibleStartFacts( +) : FlowFunctions { + override fun obtainPossibleStartFacts( method: JcMethod, ): Collection { return listOf(TaintZeroFact) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt similarity index 81% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt index 08a10d937..80df5b1bb 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt @@ -14,28 +14,27 @@ * limitations under the License. */ -package org.jacodb.ifds.unused +package org.jacodb.analysis.ifds.unused import org.jacodb.actors.impl.system import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.ifds.actors.ProjectManager +import org.jacodb.analysis.ifds.common.ClassChunkStrategy +import org.jacodb.analysis.ifds.common.JcAsyncIfdsFacade +import org.jacodb.analysis.ifds.common.JcChunkResolver +import org.jacodb.analysis.ifds.common.JcIfdsContext +import org.jacodb.analysis.ifds.common.JcIfdsFacade +import org.jacodb.analysis.ifds.common.SingletonRunnerId +import org.jacodb.analysis.ifds.domain.Vertex import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.ChunkStrategy -import org.jacodb.ifds.actors.ProjectManager -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.common.JcAsyncIfdsFacade -import org.jacodb.ifds.common.JcChunkResolver -import org.jacodb.ifds.common.JcIfdsContext -import org.jacodb.ifds.common.JcIfdsFacade -import org.jacodb.ifds.common.SingletonRunnerId -import org.jacodb.ifds.domain.Vertex fun unusedIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, + chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, ): JcIfdsContext = JcIfdsContext( cp, @@ -53,7 +52,7 @@ fun unusedIfdsFacade( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, + chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, ): JcIfdsFacade { val context = unusedIfdsContext(cp, graph, bannedPackagePrefixes, chunkStrategy) val system = system(name) { ProjectManager(context) } @@ -96,7 +95,7 @@ fun asyncUnusedIfdsFacade( cp: JcClasspath, graph: JcApplicationGraph, bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: ChunkStrategy = ClassChunkStrategy, + chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, ): JcAsyncIfdsFacade { val facade = unusedIfdsFacade(name, cp, graph, bannedPackagePrefixes, chunkStrategy) return JcAsyncIfdsFacade(facade) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Findings.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Findings.kt similarity index 87% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Findings.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Findings.kt index 8acb334ab..12b8401c4 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Findings.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Findings.kt @@ -14,11 +14,11 @@ * limitations under the License. */ -package org.jacodb.ifds.unused +package org.jacodb.analysis.ifds.unused +import org.jacodb.analysis.ifds.domain.Vertex +import org.jacodb.analysis.ifds.result.Finding import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.domain.Vertex -import org.jacodb.ifds.result.Finding data class UnusedVulnerability( val message: String, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableAnalyzer.kt similarity index 76% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableAnalyzer.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableAnalyzer.kt index 16edb7e9d..20a9b6705 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableAnalyzer.kt @@ -14,16 +14,15 @@ * limitations under the License. */ -package org.jacodb.ifds.unused +package org.jacodb.analysis.ifds.unused -import org.jacodb.api.JcMethod +import org.jacodb.analysis.ifds.common.JcBaseAnalyzer +import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.RunnerId +import org.jacodb.analysis.ifds.messages.NewSummaryEdge +import org.jacodb.analysis.ifds.messages.RunnerMessage import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.common.JcBaseAnalyzer -import org.jacodb.ifds.domain.Edge -import org.jacodb.ifds.domain.RunnerId -import org.jacodb.ifds.messages.NewSummaryEdge -import org.jacodb.ifds.messages.RunnerMessage class UnusedVariableAnalyzer( selfRunnerId: RunnerId, @@ -36,9 +35,6 @@ class UnusedVariableAnalyzer( UnusedVariableFlowFunctions(graph) } - override fun obtainPossibleStartFacts(method: JcMethod): Collection = - setOf(UnusedVariableZeroFact) - private fun isExitPoint(statement: JcInst): Boolean { return statement in graph.exitPoints(statement.location.method) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFacts.kt similarity index 91% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFacts.kt index 7215c5696..9fe971127 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFacts.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFacts.kt @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.jacodb.ifds.unused +package org.jacodb.analysis.ifds.unused +import org.jacodb.analysis.ifds.util.AccessPath import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.util.AccessPath sealed interface UnusedVariableDomainFact diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt similarity index 84% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt index 706500a9a..6c36e897f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/UnusedVariableFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt @@ -14,30 +14,34 @@ * limitations under the License. */ -package org.jacodb.ifds.unused +package org.jacodb.analysis.ifds.unused +import org.jacodb.analysis.ifds.common.FlowFunctions +import org.jacodb.analysis.ifds.util.getArgumentsOf +import org.jacodb.analysis.ifds.util.toPath +import org.jacodb.analysis.ifds.util.toPathOrNull import org.jacodb.api.JcClasspath +import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcInst import org.jacodb.api.cfg.JcSpecialCallExpr import org.jacodb.api.cfg.JcStaticCallExpr import org.jacodb.api.ext.cfg.callExpr -import org.jacodb.ifds.common.FlowFunctions -import org.jacodb.ifds.util.getArgumentsOf -import org.jacodb.ifds.util.toPath -import org.jacodb.ifds.util.toPathOrNull class UnusedVariableFlowFunctions( private val graph: JcApplicationGraph, -) : FlowFunctions { +) : FlowFunctions { private val cp: JcClasspath get() = graph.classpath + override fun obtainPossibleStartFacts(method: JcMethod): Collection = + setOf(UnusedVariableZeroFact) + override fun sequent( current: JcInst, next: JcInst, - fact: UnusedVariableDomainFact + fact: UnusedVariableDomainFact, ): Collection { if (current !is JcAssignInst) { return setOf(fact) @@ -72,13 +76,13 @@ class UnusedVariableFlowFunctions( override fun callToReturn( callStatement: JcInst, returnSite: JcInst, - fact: UnusedVariableDomainFact + fact: UnusedVariableDomainFact, ): Collection = sequent(callStatement, returnSite, fact) override fun callToStart( callStatement: JcInst, calleeStart: JcInst, - fact: UnusedVariableDomainFact + fact: UnusedVariableDomainFact, ): Collection { val callExpr = callStatement.callExpr ?: error("Call statement should have non-null callExpr") @@ -105,7 +109,7 @@ class UnusedVariableFlowFunctions( callStatement: JcInst, returnSite: JcInst, exitStatement: JcInst, - fact: UnusedVariableDomainFact + fact: UnusedVariableDomainFact, ): Collection { return if (fact == UnusedVariableZeroFact) { setOf(UnusedVariableZeroFact) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Utils.kt similarity index 93% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Utils.kt index 2eb940ee3..d2addb076 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/unused/Utils.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Utils.kt @@ -14,8 +14,10 @@ * limitations under the License. */ -package org.jacodb.ifds.unused +package org.jacodb.analysis.ifds.unused +import org.jacodb.analysis.ifds.util.AccessPath +import org.jacodb.analysis.ifds.util.toPathOrNull import org.jacodb.api.cfg.JcArrayAccess import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcBranchingInst @@ -26,8 +28,6 @@ import org.jacodb.api.cfg.JcSpecialCallExpr import org.jacodb.api.cfg.JcTerminatingInst import org.jacodb.api.cfg.values import org.jacodb.api.ext.cfg.callExpr -import org.jacodb.ifds.util.AccessPath -import org.jacodb.ifds.util.toPathOrNull internal fun AccessPath.isUsedAt(expr: JcExpr): Boolean { return expr.values.any { it.toPathOrNull() == this } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/AccessPath.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/AccessPath.kt similarity index 98% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/AccessPath.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/AccessPath.kt index c184151c5..c36b8c694 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/AccessPath.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/AccessPath.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.util +package org.jacodb.analysis.ifds.util import org.jacodb.api.JcField import org.jacodb.api.cfg.JcArrayAccess diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Accessors.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/Accessors.kt similarity index 96% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Accessors.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/Accessors.kt index 443a916ee..3c503d520 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Accessors.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/Accessors.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.util +package org.jacodb.analysis.ifds.util import org.jacodb.api.JcField diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Extensions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/Extensions.kt similarity index 97% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Extensions.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/Extensions.kt index d18ca073a..3c76a4d2e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Extensions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/Extensions.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.util +package org.jacodb.analysis.ifds.util import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Maybe.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/Maybe.kt similarity index 97% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Maybe.kt rename to jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/Maybe.kt index 9505789f2..31ab16bd2 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/ifds/util/Maybe.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/util/Maybe.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.ifds.util +package org.jacodb.analysis.ifds.util @JvmInline value class Maybe private constructor( diff --git a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java similarity index 89% rename from jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java rename to jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java index be0eeb0a3..aac82b5e5 100644 --- a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/impl/JavaAnalysisApiTest.java +++ b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java @@ -14,19 +14,19 @@ * limitations under the License. */ -package org.jacodb.analysis.impl; +package org.jacodb.analysis.ifds; import kotlin.time.DurationUnit; import org.jacodb.analysis.graph.ApplicationGraphFactory; +import org.jacodb.analysis.ifds.common.ChunkStrategiesKt; +import org.jacodb.analysis.ifds.common.JcAsyncIfdsFacade; +import org.jacodb.analysis.ifds.taint.TaintDomainFact; +import org.jacodb.analysis.ifds.taint.TaintVulnerability; import org.jacodb.api.JcClassOrInterface; import org.jacodb.api.JcClasspath; import org.jacodb.api.JcDatabase; import org.jacodb.api.JcMethod; import org.jacodb.api.analysis.JcApplicationGraph; -import org.jacodb.ifds.common.ChunkStrategiesKt; -import org.jacodb.ifds.common.JcAsyncIfdsFacade; -import org.jacodb.ifds.taint.TaintDomainFact; -import org.jacodb.ifds.taint.TaintVulnerability; import org.jacodb.impl.JacoDB; import org.jacodb.impl.JcSettings; import org.jacodb.impl.features.InMemoryHierarchy; @@ -41,7 +41,7 @@ import static kotlin.time.DurationKt.toDuration; import static org.jacodb.analysis.graph.ApplicationGraphFactory.getDefaultBannedPackagePrefixes; -import static org.jacodb.ifds.taint.BuildersKt.asyncTaintIfdsFacade; +import static org.jacodb.analysis.ifds.taint.BuildersKt.asyncTaintIfdsFacade; public class JavaAnalysisApiTest { diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/BaseAnalysisTest.kt similarity index 98% rename from jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/BaseAnalysisTest.kt index 7d419d61e..d86c6059a 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/BaseAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/BaseAnalysisTest.kt @@ -14,17 +14,17 @@ * limitations under the License. */ -package org.jacodb.analysis.impl +package org.jacodb.analysis.ifds import juliet.support.AbstractTestCase import kotlinx.coroutines.runBlocking import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.ifds.result.Finding import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods -import org.jacodb.ifds.result.Finding import org.jacodb.impl.features.classpaths.UnknownClasses import org.jacodb.impl.features.hierarchyExt import org.jacodb.impl.features.usagesExt diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/ConditionEvaluatorTest.kt similarity index 96% rename from jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/ConditionEvaluatorTest.kt index 4fc978cd8..b1d249595 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/ConditionEvaluatorTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/ConditionEvaluatorTest.kt @@ -14,16 +14,16 @@ * limitations under the License. */ -package org.jacodb.analysis.impl +package org.jacodb.analysis.ifds import io.mockk.every import io.mockk.mockk -import org.jacodb.ifds.config.BasicConditionEvaluator -import org.jacodb.ifds.config.FactAwareConditionEvaluator -import org.jacodb.ifds.util.Maybe -import org.jacodb.ifds.util.toMaybe -import org.jacodb.ifds.util.toPath -import org.jacodb.ifds.taint.Tainted +import org.jacodb.analysis.ifds.config.BasicConditionEvaluator +import org.jacodb.analysis.ifds.config.FactAwareConditionEvaluator +import org.jacodb.analysis.ifds.taint.Tainted +import org.jacodb.analysis.ifds.util.Maybe +import org.jacodb.analysis.ifds.util.toMaybe +import org.jacodb.analysis.ifds.util.toPath import org.jacodb.api.JcClasspath import org.jacodb.api.JcPrimitiveType import org.jacodb.api.JcType diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsNpeTest.kt similarity index 98% rename from jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsNpeTest.kt index 99e8d0c35..f83e0cbac 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsNpeTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsNpeTest.kt @@ -14,15 +14,15 @@ * limitations under the License. */ -package org.jacodb.analysis.impl +package org.jacodb.analysis.ifds import kotlinx.coroutines.runBlocking import org.jacodb.analysis.graph.JcApplicationGraphImpl +import org.jacodb.analysis.ifds.npe.NpeVulnerability +import org.jacodb.analysis.ifds.npe.npeIfdsFacade import org.jacodb.api.JcMethod import org.jacodb.api.ext.constructors import org.jacodb.api.ext.findClass -import org.jacodb.ifds.npe.NpeVulnerability -import org.jacodb.ifds.npe.npeIfdsFacade import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.impl.features.usagesExt diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt similarity index 91% rename from jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt index 62d808fa8..4286a0c67 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsSqlTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt @@ -14,21 +14,21 @@ * limitations under the License. */ -package org.jacodb.analysis.impl +package org.jacodb.analysis.ifds import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.ifds.result.buildTraceGraph +import org.jacodb.analysis.ifds.sarif.sarifReportFromVulnerabilities +import org.jacodb.analysis.ifds.sarif.toSarif +import org.jacodb.analysis.ifds.taint.TaintVulnerability +import org.jacodb.analysis.ifds.taint.TaintZeroFact +import org.jacodb.analysis.ifds.taint.taintIfdsFacade import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods -import org.jacodb.ifds.result.buildTraceGraph -import org.jacodb.ifds.sarif.sarifReportFromVulnerabilities -import org.jacodb.ifds.sarif.toSarif -import org.jacodb.ifds.taint.TaintVulnerability -import org.jacodb.ifds.taint.TaintZeroFact -import org.jacodb.ifds.taint.taintIfdsFacade import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.testing.WithDB diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt similarity index 95% rename from jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt index a668c276a..7c516a511 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/IfdsUnusedTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt @@ -14,15 +14,15 @@ * limitations under the License. */ -package org.jacodb.analysis.impl +package org.jacodb.analysis.ifds import kotlinx.coroutines.runBlocking import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.ifds.unused.UnusedVulnerability +import org.jacodb.analysis.ifds.unused.unusedIfdsFacade import org.jacodb.api.JcMethod import org.jacodb.api.ext.findClass import org.jacodb.api.ext.methods -import org.jacodb.ifds.unused.UnusedVulnerability -import org.jacodb.ifds.unused.unusedIfdsFacade import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.testing.WithDB diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt similarity index 94% rename from jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt index 1b7296c0b..9b469edd4 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt @@ -14,17 +14,17 @@ * limitations under the License. */ -package org.jacodb.analysis.impl +package org.jacodb.analysis.ifds import kotlinx.coroutines.runBlocking import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.ifds.npe.npeIfdsFacade +import org.jacodb.analysis.ifds.taint.taintIfdsFacade +import org.jacodb.analysis.ifds.unused.unusedIfdsFacade import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.ext.findClass -import org.jacodb.ifds.npe.npeIfdsFacade -import org.jacodb.ifds.taint.taintIfdsFacade -import org.jacodb.ifds.unused.unusedIfdsFacade import org.jacodb.impl.features.usagesExt import org.jacodb.taint.configuration.TaintConfigurationFeature import org.jacodb.testing.BaseTest diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt similarity index 88% rename from jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt rename to jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt index 2bea5395c..d4db356aa 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/impl/TaintFlowFunctionsTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt @@ -14,17 +14,17 @@ * limitations under the License. */ -package org.jacodb.analysis.impl +package org.jacodb.analysis.ifds import io.mockk.every import io.mockk.mockk -import org.jacodb.ifds.common.FlowFunctions -import org.jacodb.ifds.util.toPath -import org.jacodb.ifds.taint.ForwardTaintFlowFunctions -import org.jacodb.ifds.taint.TaintDomainFact -import org.jacodb.ifds.taint.TaintZeroFact -import org.jacodb.ifds.taint.Tainted -import org.jacodb.ifds.util.getArgument +import org.jacodb.analysis.ifds.common.FlowFunctions +import org.jacodb.analysis.ifds.taint.ForwardTaintFlowFunctions +import org.jacodb.analysis.ifds.taint.TaintDomainFact +import org.jacodb.analysis.ifds.taint.TaintZeroFact +import org.jacodb.analysis.ifds.taint.Tainted +import org.jacodb.analysis.ifds.util.getArgument +import org.jacodb.analysis.ifds.util.toPath import org.jacodb.api.JcClassType import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph @@ -108,7 +108,7 @@ class TaintFlowFunctionsTest : BaseTest() { val x: JcLocal = JcLocalVar(1, "x", stringType) val y: JcLocal = JcLocalVar(2, "y", stringType) val inst = JcAssignInst(location = mockk(), lhv = x, rhv = y) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val facts = flowSpace.sequent(inst, next = mockk(), yTaint).toList() @@ -124,7 +124,7 @@ class TaintFlowFunctionsTest : BaseTest() { every { method } returns testMethod } }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("EXAMPLE")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), TaintZeroFact).toList() Assertions.assertEquals(listOf(TaintZeroFact, xTaint), facts) @@ -140,7 +140,7 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("REMOVE")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() Assertions.assertTrue(facts.isEmpty()) @@ -157,7 +157,7 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("COPY")) val yTaint = Tainted(y.toPath(), TaintMark("COPY")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() @@ -178,7 +178,7 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val arg0: JcArgument = cp.getArgument(testMethod.parameters[0])!! @@ -217,7 +217,7 @@ class TaintFlowFunctionsTest : BaseTest() { val exitStatement = JcReturnInst(location = mockk { every { method } returns testMethod }, returnValue = y) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val facts = flowSpace.exitToReturnSite(callStatement, returnSite = mockk(), exitStatement, yTaint).toList() diff --git a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt index 94092d47e..99fdac552 100644 --- a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt +++ b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt @@ -28,23 +28,23 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.encodeToStream import org.jacodb.analysis.graph.JcApplicationGraphImpl import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.ifds.taint.TaintZeroFact +import org.jacodb.analysis.ifds.taint.TaintZeroFact import org.jacodb.api.JcClassOrInterface import org.jacodb.api.JcClassProcessingTask import org.jacodb.api.JcMethod import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst -import org.jacodb.ifds.common.ClassChunkStrategy -import org.jacodb.ifds.common.MethodChunkStrategy -import org.jacodb.ifds.common.PackageChunkStrategy -import org.jacodb.ifds.common.SingletonChunkStrategy -import org.jacodb.ifds.npe.npeIfdsFacade -import org.jacodb.ifds.result.buildTraceGraph -import org.jacodb.ifds.sarif.VulnerabilityInstance -import org.jacodb.ifds.sarif.sarifReportFromVulnerabilities -import org.jacodb.ifds.sarif.toSarif -import org.jacodb.ifds.taint.taintIfdsFacade -import org.jacodb.ifds.unused.unusedIfdsFacade +import org.jacodb.analysis.ifds.common.ClassChunkStrategy +import org.jacodb.analysis.ifds.common.MethodChunkStrategy +import org.jacodb.analysis.ifds.common.PackageChunkStrategy +import org.jacodb.analysis.ifds.common.SingletonChunkStrategy +import org.jacodb.analysis.ifds.npe.npeIfdsFacade +import org.jacodb.analysis.ifds.result.buildTraceGraph +import org.jacodb.analysis.ifds.sarif.VulnerabilityInstance +import org.jacodb.analysis.ifds.sarif.sarifReportFromVulnerabilities +import org.jacodb.analysis.ifds.sarif.toSarif +import org.jacodb.analysis.ifds.taint.taintIfdsFacade +import org.jacodb.analysis.ifds.unused.unusedIfdsFacade import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.impl.features.usagesExt diff --git a/settings.gradle.kts b/settings.gradle.kts index 4dc0c23aa..1a2a606f3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,7 @@ rootProject.name = "jacodb" plugins { `gradle-enterprise` id("org.danilopianini.gradle-pre-commit-git-hooks") version "1.1.11" + id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0" } gradleEnterprise { @@ -26,7 +27,7 @@ include("jacodb-benchmarks") include("jacodb-cli") include("jacodb-approximations") include("jacodb-taint-configuration") +include("jacodb-analysis:common") include("jacodb-analysis:actors") include("jacodb-analysis:ifds") include("jacodb-analysis:taint") -findProject(":jacodb-analysis:taint")?.name = "taint" From e1f2e0e99e4af591205c4248d0c599981623f3ec Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Wed, 15 May 2024 22:28:40 +0300 Subject: [PATCH 49/64] [ifds] wip: graph factory --- .../analysis/graph/ApplicationGraphFactory.kt | 47 ------------------- .../analysis/graph/JcApplicationGraphImpl.kt | 11 +++++ .../analysis/ifds/common/BannedPackages.kt | 26 ++++++++++ .../org/jacodb/analysis/ifds/npe/Builders.kt | 2 +- .../jacodb/analysis/ifds/taint/Builders.kt | 2 +- .../jacodb/analysis/ifds/unused/Builders.kt | 2 +- .../analysis/ifds/JavaAnalysisApiTest.java | 14 +++--- .../org/jacodb/analysis/ifds/IfdsSqlTest.kt | 2 +- .../jacodb/analysis/ifds/IfdsUnusedTest.kt | 2 +- .../analysis/ifds/JodaDateTimeAnalysisTest.kt | 2 +- .../src/main/kotlin/org/jacodb/cli/main.kt | 14 +++--- 11 files changed, 57 insertions(+), 67 deletions(-) delete mode 100644 jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt create mode 100644 jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/BannedPackages.kt diff --git a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt deleted file mode 100644 index 973e66b50..000000000 --- a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/ApplicationGraphFactory.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2022 UnitTestBot contributors (utbot.org) - *

- * 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 - *

- * 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. - */ - -@file:JvmName("ApplicationGraphFactory") - -package org.jacodb.analysis.graph - -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.future.future -import org.jacodb.api.JcClasspath -import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.impl.features.usagesExt -import java.util.concurrent.CompletableFuture - -/** - * Async adapter for calling [newApplicationGraphForAnalysis] from Java. - * - * See also: [answer on StackOverflow](https://stackoverflow.com/a/52887677/3592218). - */ -@OptIn(DelicateCoroutinesApi::class) -fun JcClasspath.newApplicationGraphForAnalysisAsync(): CompletableFuture = - GlobalScope.future { - JcApplicationGraphImpl(this@newApplicationGraphForAnalysisAsync, usagesExt()) - } - -val defaultBannedPackagePrefixes: List = listOf( - "kotlin.", - "java.", - "jdk.internal.", - "sun.", - "com.sun.", - "javax.", -) diff --git a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt index 2909cfd65..ed5dbffc4 100644 --- a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt @@ -16,12 +16,17 @@ package org.jacodb.analysis.graph +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.future.future 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.cfg.callExpr import org.jacodb.impl.features.SyncUsagesExtension +import org.jacodb.impl.features.usagesExt +import java.util.concurrent.CompletableFuture /** * Possible we will need JcRawInst instead of JcInst @@ -70,3 +75,9 @@ open class JcApplicationGraphImpl( return node.location.method } } + +@OptIn(DelicateCoroutinesApi::class) +fun JcClasspath.newApplicationGraphForAnalysisAsync(): CompletableFuture = + GlobalScope.future { + JcApplicationGraphImpl(this@newApplicationGraphForAnalysisAsync, usagesExt()) + } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/BannedPackages.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/BannedPackages.kt new file mode 100644 index 000000000..d7e3030bf --- /dev/null +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/BannedPackages.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.analysis.ifds.common + +val defaultBannedPackagePrefixes: List = listOf( + "kotlin.", + "java.", + "jdk.internal.", + "sun.", + "com.sun.", + "javax.", +) \ No newline at end of file diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt index 575e2f409..706598dc6 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt @@ -17,7 +17,6 @@ package org.jacodb.analysis.ifds.npe import org.jacodb.actors.impl.system -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.actors.ProjectManager import org.jacodb.analysis.ifds.common.ClassChunkStrategy import org.jacodb.analysis.ifds.common.JcAsyncIfdsFacade @@ -25,6 +24,7 @@ import org.jacodb.analysis.ifds.common.JcChunkResolver import org.jacodb.analysis.ifds.common.JcIfdsContext import org.jacodb.analysis.ifds.common.JcIfdsFacade import org.jacodb.analysis.ifds.common.SingletonRunnerId +import org.jacodb.analysis.ifds.common.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.taint.TaintDomainFact import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt index 345dcbb8e..54f57ffd5 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt @@ -17,7 +17,6 @@ package org.jacodb.analysis.ifds.taint import org.jacodb.actors.impl.system -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.actors.ProjectManager import org.jacodb.analysis.ifds.common.BackwardRunnerId import org.jacodb.analysis.ifds.common.ClassChunkStrategy @@ -26,6 +25,7 @@ import org.jacodb.analysis.ifds.common.JcAsyncIfdsFacade import org.jacodb.analysis.ifds.common.JcChunkResolver import org.jacodb.analysis.ifds.common.JcIfdsContext import org.jacodb.analysis.ifds.common.JcIfdsFacade +import org.jacodb.analysis.ifds.common.defaultBannedPackagePrefixes import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt index 80df5b1bb..292e5699f 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt @@ -17,7 +17,6 @@ package org.jacodb.analysis.ifds.unused import org.jacodb.actors.impl.system -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.actors.ProjectManager import org.jacodb.analysis.ifds.common.ClassChunkStrategy import org.jacodb.analysis.ifds.common.JcAsyncIfdsFacade @@ -25,6 +24,7 @@ import org.jacodb.analysis.ifds.common.JcChunkResolver import org.jacodb.analysis.ifds.common.JcIfdsContext import org.jacodb.analysis.ifds.common.JcIfdsFacade import org.jacodb.analysis.ifds.common.SingletonRunnerId +import org.jacodb.analysis.ifds.common.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.domain.Vertex import org.jacodb.api.JcClasspath import org.jacodb.api.analysis.JcApplicationGraph diff --git a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java index aac82b5e5..f794ad9e1 100644 --- a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java +++ b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java @@ -17,7 +17,6 @@ package org.jacodb.analysis.ifds; import kotlin.time.DurationUnit; -import org.jacodb.analysis.graph.ApplicationGraphFactory; import org.jacodb.analysis.ifds.common.ChunkStrategiesKt; import org.jacodb.analysis.ifds.common.JcAsyncIfdsFacade; import org.jacodb.analysis.ifds.taint.TaintDomainFact; @@ -40,7 +39,8 @@ import java.util.concurrent.ExecutionException; import static kotlin.time.DurationKt.toDuration; -import static org.jacodb.analysis.graph.ApplicationGraphFactory.getDefaultBannedPackagePrefixes; +import static org.jacodb.analysis.graph.JcApplicationGraphImplKt.newApplicationGraphForAnalysisAsync; +import static org.jacodb.analysis.ifds.common.BannedPackagesKt.getDefaultBannedPackagePrefixes; import static org.jacodb.analysis.ifds.taint.BuildersKt.asyncTaintIfdsFacade; @@ -59,9 +59,9 @@ public void testJavaAnalysisApi() throws ExecutionException, InterruptedExceptio Assertions.assertNotNull(analyzedClass); List methodsToAnalyze = analyzedClass.getDeclaredMethods(); - JcApplicationGraph applicationGraph = ApplicationGraphFactory - .newApplicationGraphForAnalysisAsync(classpath) - .get(); + JcApplicationGraph applicationGraph = + newApplicationGraphForAnalysisAsync(classpath) + .get(); JcAsyncIfdsFacade ifds = asyncTaintIfdsFacade( "ifds", @@ -70,8 +70,8 @@ public void testJavaAnalysisApi() throws ExecutionException, InterruptedExceptio getDefaultBannedPackagePrefixes(), ChunkStrategiesKt.getClassChunkStrategy()); ifds.runAnalysis( - methodsToAnalyze, - toDuration(30, DurationUnit.SECONDS)) + methodsToAnalyze, + toDuration(30, DurationUnit.SECONDS)) .get(); } } diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt index 4286a0c67..fb1ef6505 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt @@ -19,7 +19,7 @@ package org.jacodb.analysis.ifds import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.ifds.common.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.result.buildTraceGraph import org.jacodb.analysis.ifds.sarif.sarifReportFromVulnerabilities import org.jacodb.analysis.ifds.sarif.toSarif diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt index 7c516a511..387616437 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt @@ -17,7 +17,7 @@ package org.jacodb.analysis.ifds import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.ifds.common.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.unused.UnusedVulnerability import org.jacodb.analysis.ifds.unused.unusedIfdsFacade import org.jacodb.api.JcMethod diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt index 9b469edd4..2da62bc0e 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt @@ -18,7 +18,7 @@ package org.jacodb.analysis.ifds import kotlinx.coroutines.runBlocking import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes +import org.jacodb.analysis.ifds.common.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.npe.npeIfdsFacade import org.jacodb.analysis.ifds.taint.taintIfdsFacade import org.jacodb.analysis.ifds.unused.unusedIfdsFacade diff --git a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt index 99fdac552..187364f20 100644 --- a/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt +++ b/jacodb-cli/src/main/kotlin/org/jacodb/cli/main.kt @@ -27,24 +27,24 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.encodeToStream import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.graph.defaultBannedPackagePrefixes -import org.jacodb.analysis.ifds.taint.TaintZeroFact -import org.jacodb.api.JcClassOrInterface -import org.jacodb.api.JcClassProcessingTask -import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph -import org.jacodb.api.cfg.JcInst import org.jacodb.analysis.ifds.common.ClassChunkStrategy import org.jacodb.analysis.ifds.common.MethodChunkStrategy import org.jacodb.analysis.ifds.common.PackageChunkStrategy import org.jacodb.analysis.ifds.common.SingletonChunkStrategy +import org.jacodb.analysis.ifds.common.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.npe.npeIfdsFacade import org.jacodb.analysis.ifds.result.buildTraceGraph import org.jacodb.analysis.ifds.sarif.VulnerabilityInstance import org.jacodb.analysis.ifds.sarif.sarifReportFromVulnerabilities import org.jacodb.analysis.ifds.sarif.toSarif +import org.jacodb.analysis.ifds.taint.TaintZeroFact import org.jacodb.analysis.ifds.taint.taintIfdsFacade import org.jacodb.analysis.ifds.unused.unusedIfdsFacade +import org.jacodb.api.JcClassOrInterface +import org.jacodb.api.JcClassProcessingTask +import org.jacodb.api.JcMethod +import org.jacodb.api.analysis.JcApplicationGraph +import org.jacodb.api.cfg.JcInst import org.jacodb.impl.features.InMemoryHierarchy import org.jacodb.impl.features.Usages import org.jacodb.impl.features.usagesExt From 1591d8b4d6b357352264c43315a88bf2a834356e Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 16 May 2024 00:11:06 +0300 Subject: [PATCH 50/64] [ifds] wip: remove graph dependency from flow functions, add NoResolvedCall --- .../analysis/ifds/common/JcAsyncIfdsFacade.kt | 2 + .../analysis/ifds/common/JcBaseAnalyzer.kt | 31 ++++--- .../analysis/ifds/common/JcChunkResolver.kt | 6 ++ .../ifds/common/JcIndirectionHandler.kt | 41 ++++----- .../jacodb/analysis/ifds/npe/NpeAnalyzers.kt | 11 ++- .../analysis/ifds/npe/NpeFlowFunctions.kt | 47 ++++------ .../analysis/ifds/taint/TaintAnalyzers.kt | 14 +-- .../analysis/ifds/taint/TaintFlowFunctions.kt | 86 +++++++------------ .../ifds/unused/UnusedVariableAnalyzer.kt | 10 +-- .../unused/UnusedVariableFlowFunctions.kt | 5 +- .../analysis/ifds/TaintFlowFunctionsTest.kt | 42 +++++---- 11 files changed, 140 insertions(+), 155 deletions(-) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcAsyncIfdsFacade.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcAsyncIfdsFacade.kt index 9bfbff5b5..a3931fafe 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcAsyncIfdsFacade.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcAsyncIfdsFacade.kt @@ -18,6 +18,7 @@ package org.jacodb.analysis.ifds.common import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel import kotlinx.coroutines.future.future import org.jacodb.analysis.ifds.result.Finding import org.jacodb.api.JcMethod @@ -58,5 +59,6 @@ class JcAsyncIfdsFacade>( override fun close() { ifdsFacade.close() + scope.cancel() } } \ No newline at end of file diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt index e7420ed5f..b51c0f3f9 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt @@ -50,16 +50,11 @@ abstract class JcBaseAnalyzer( is ResolvedCall -> { @Suppress("UNCHECKED_CAST") message as ResolvedCall - processResolvedCall( - message.edge, - message.method - ) + processResolvedCall(message.edge, message.method) } is NoResolvedCall -> { - processNoResolvedCall( - message.edge - ) + processNoResolvedCall(message.edge) } is NotificationOnStart -> { @@ -147,18 +142,32 @@ abstract class JcBaseAnalyzer( } } - private fun processNoResolvedCall(edge: Edge) { - TODO("Not yet implemented") + private fun MutableList.processNoResolvedCall(edge: Edge) { + val reason = Reason.Sequent(edge) + + val successors = graph.successors(edge.to.statement) + + for (successor in successors) { + val facts = flowFunctions.sequent( + current = edge.to.statement, + next = successor, + edge.to.fact + ) + for (fact in facts) { + val newEdge = Edge(edge.from, Vertex(successor, fact)) + processNewEdge(selfRunnerId, newEdge, reason) + } + } } private fun MutableList.processNotificationOnStart( callerEdge: Edge, edge: Edge ) { - val returnSites = graph.successors(callerEdge.to.statement) - val reason = Reason.ExitToReturnSite(callerEdge, edge) + val returnSites = graph.successors(callerEdge.to.statement) + for (returnSite in returnSites) { val facts = flowFunctions.exitToReturnSite( callStatement = callerEdge.to.statement, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt index a456d4556..4c704bca2 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt @@ -24,6 +24,7 @@ import org.jacodb.analysis.ifds.messages.IndirectionMessage import org.jacodb.analysis.ifds.messages.NewEdge import org.jacodb.analysis.ifds.messages.NewFinding import org.jacodb.analysis.ifds.messages.NewSummaryEdge +import org.jacodb.analysis.ifds.messages.NoResolvedCall import org.jacodb.analysis.ifds.messages.NotificationOnEnd import org.jacodb.analysis.ifds.messages.NotificationOnStart import org.jacodb.analysis.ifds.messages.ResolvedCall @@ -64,6 +65,11 @@ class JcChunkResolver( chunkStrategy.chunkByStmt(message.edge.to.statement) } + is NoResolvedCall<*, *> -> { + message as NoResolvedCall + chunkStrategy.chunkByStmt(message.edge.to.statement) + } + else -> { error("Unexpected message: $message") } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt index 9910ecbf5..7e7c33b7c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt @@ -19,6 +19,7 @@ package org.jacodb.analysis.ifds.common import org.jacodb.analysis.ifds.domain.IndirectionHandler import org.jacodb.analysis.ifds.domain.RunnerId import org.jacodb.analysis.ifds.messages.IndirectionMessage +import org.jacodb.analysis.ifds.messages.NoResolvedCall import org.jacodb.analysis.ifds.messages.ResolvedCall import org.jacodb.analysis.ifds.messages.RunnerMessage import org.jacodb.analysis.ifds.messages.UnresolvedCall @@ -38,35 +39,31 @@ class JcIndirectionHandler( ) : IndirectionHandler { private val cache = hashMapOf>() - override fun handle(message: IndirectionMessage): Collection { @Suppress("UNCHECKED_CAST") - message as? UnresolvedCall ?: return emptyList() + message as? UnresolvedCall ?: error("Unexpected message: $message") - val node = message.edge.to.statement + val edge = message.edge + val node = edge.to.statement - val callees = (node.callExpr?.let { listOf(it.method.method) } ?: emptyList()) - .filterNot { callee -> - bannedPackagePrefixes.any { callee.enclosingClass.name.startsWith(it) } - } + val callExpr = node.callExpr ?: return emptyList() + val callee = callExpr.method.method + if (bannedPackagePrefixes.any { callee.enclosingClass.name.startsWith(it) }) { + return listOf(NoResolvedCall(runnerId, edge)) + } - val callExpr = node.callExpr as? JcVirtualCallExpr - ?: return callees.map { ResolvedCall(runnerId, message.edge, it) } + if (callExpr !is JcVirtualCallExpr) { + return listOf(ResolvedCall(runnerId, edge, callee)) + } val instanceClass = (callExpr.instance.type as? JcClassType)?.jcClass - ?: return listOf(ResolvedCall(runnerId, message.edge, callExpr.method.method)) + ?: return listOf(ResolvedCall(runnerId, edge, callee)) + - return callees - .flatMap { callee -> - val allOverrides = cache.computeIfAbsent(callee) { - hierarchy.findOverrides(callee).toList() - }.filter { - it.enclosingClass isSubClassOf instanceClass || - // TODO: use only down-most override here - instanceClass isSubClassOf it.enclosingClass - }.asSequence() - // TODO: maybe filter inaccessible methods here? - allOverrides + sequenceOf(callee) - }.mapTo(mutableListOf()) { ResolvedCall(runnerId, message.edge, it) } + val overrides = cache + .computeIfAbsent(callee) { hierarchy.findOverrides(callee).toList() } + .asSequence() + .filter { it.enclosingClass isSubClassOf instanceClass } + return (overrides + callee).mapTo(mutableListOf()) { ResolvedCall(runnerId, edge, it) } } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt index d1f17ccff..1627e0f57 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt @@ -43,7 +43,7 @@ class NpeAnalyzer( selfRunnerId, graph ) { - val cp = graph.classpath + private val cp = graph.classpath private val taintConfigurationFeature: TaintConfigurationFeature? by lazy { cp.features @@ -53,11 +53,7 @@ class NpeAnalyzer( override val flowFunctions: ForwardNpeFlowFunctions by lazy { - ForwardNpeFlowFunctions(cp, graph, taintConfigurationFeature) - } - - private fun isExitPoint(statement: JcInst): Boolean { - return statement in graph.exitPoints(statement.location.method) + ForwardNpeFlowFunctions(cp, taintConfigurationFeature) } override fun MutableList.onNewEdge(newEdge: Edge) { @@ -103,4 +99,7 @@ class NpeAnalyzer( } } + private fun isExitPoint(statement: JcInst): Boolean { + return statement in graph.exitPoints(statement.location.method) + } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt index b9d57b1b7..17070d350 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt @@ -38,7 +38,6 @@ import org.jacodb.analysis.ifds.util.toPathOrNull import org.jacodb.api.JcArrayType import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcArgument import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcCallExpr @@ -73,7 +72,6 @@ private val logger = mu.KotlinLogging.logger {} class ForwardNpeFlowFunctions( private val cp: JcClasspath, - private val graph: JcApplicationGraph, private val taintConfigurationFeature: TaintConfigurationFeature?, ) : FlowFunctions { override fun obtainPossibleStartFacts( @@ -208,7 +206,7 @@ class ForwardNpeFlowFunctions( override fun sequent( current: JcInst, next: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { if (fact.variable.isDereferencedAt(current)) { @@ -315,7 +313,7 @@ class ForwardNpeFlowFunctions( override fun callToReturn( callStatement: JcInst, returnSite: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { if (fact.variable.isDereferencedAt(callStatement)) { @@ -448,35 +446,22 @@ class ForwardNpeFlowFunctions( return listOf(fact) } - // TODO: CONSIDER REFACTORING THIS - // Default behavior for "analyzable" method calls is to remove ("temporarily") - // all the marks from the 'instance' and arguments, in order to allow them "pass through" - // the callee (when it is going to be analyzed), i.e. through "call-to-start" and - // "exit-to-return" flow functions. - // When we know that we are NOT going to analyze the callee, we do NOT need - // to remove any marks from 'instance' and arguments. - // Currently, "analyzability" of the callee depends on the fact that the callee - // is "accessible" through the JcApplicationGraph::callees(). - if (callee in graph.callees(callStatement)) { - - if (fact.variable.isStatic) { - return emptyList() - } + if (fact.variable.isStatic) { + return emptyList() + } - for (actual in callExpr.args) { - // Possibly tainted actual parameter: - if (fact.variable.startsWith(actual.toPathOrNull())) { - return emptyList() // Will be handled by summary edge - } + for (actual in callExpr.args) { + // Possibly tainted actual parameter: + if (fact.variable.startsWith(actual.toPathOrNull())) { + return emptyList() // Will be handled by summary edge } + } - if (callExpr is JcInstanceCallExpr) { - // Possibly tainted instance: - if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return emptyList() // Will be handled by summary edge - } + if (callExpr is JcInstanceCallExpr) { + // Possibly tainted instance: + if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { + return emptyList() // Will be handled by summary edge } - } if (callStatement is JcAssignInst) { @@ -493,7 +478,7 @@ class ForwardNpeFlowFunctions( override fun callToStart( callStatement: JcInst, calleeStart: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { val callee = calleeStart.location.method @@ -543,7 +528,7 @@ class ForwardNpeFlowFunctions( callStatement: JcInst, returnSite: JcInst, exitStatement: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { // TODO: do we even need to return non-empty list for zero fact here? if (fact == TaintZeroFact) { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt index e413110e8..f4d224916 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt @@ -32,6 +32,7 @@ import org.jacodb.taint.configuration.TaintMethodSink private val logger = mu.KotlinLogging.logger {} + class ForwardTaintAnalyzer( selfRunnerId: RunnerId, graph: JcApplicationGraph, @@ -39,18 +40,16 @@ class ForwardTaintAnalyzer( selfRunnerId, graph, ) { + private val cp = graph.classpath + private val taintConfigurationFeature: TaintConfigurationFeature? by lazy { - graph.classpath.features + cp.features ?.singleOrNull { it is TaintConfigurationFeature } ?.let { it as TaintConfigurationFeature } } override val flowFunctions by lazy { - ForwardTaintFlowFunctions(graph.classpath, graph, taintConfigurationFeature) - } - - private fun isExitPoint(statement: JcInst): Boolean { - return statement in graph.exitPoints(statement.location.method) + ForwardTaintFlowFunctions(cp, taintConfigurationFeature) } override fun MutableList.onNewEdge(newEdge: Edge) { @@ -87,4 +86,7 @@ class ForwardTaintAnalyzer( } } + private fun isExitPoint(statement: JcInst): Boolean { + return statement in graph.exitPoints(statement.location.method) + } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt index 9fe5751cf..a6d9955b4 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt @@ -33,7 +33,6 @@ import org.jacodb.analysis.ifds.util.toPath import org.jacodb.analysis.ifds.util.toPathOrNull import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcArrayAccess import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcDynamicCallExpr @@ -59,7 +58,6 @@ private val logger = mu.KotlinLogging.logger {} class ForwardTaintFlowFunctions( private val cp: JcClasspath, - private val graph: JcApplicationGraph, private val taintConfigurationFeature: TaintConfigurationFeature?, ) : FlowFunctions { @@ -141,7 +139,7 @@ class ForwardTaintFlowFunctions( override fun sequent( current: JcInst, next: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { if (fact is TaintZeroFact) { return listOf(TaintZeroFact) @@ -202,7 +200,7 @@ class ForwardTaintFlowFunctions( override fun callToReturn( callStatement: JcInst, returnSite: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { val callExpr = callStatement.callExpr ?: error("Call statement should have non-null callExpr") @@ -309,35 +307,22 @@ class ForwardTaintFlowFunctions( return listOf(fact) } - // TODO: CONSIDER REFACTORING THIS - // Default behavior for "analyzable" method calls is to remove ("temporarily") - // all the marks from the 'instance' and arguments, in order to allow them "pass through" - // the callee (when it is going to be analyzed), i.e. through "call-to-start" and - // "exit-to-return" flow functions. - // When we know that we are NOT going to analyze the callee, we do NOT need - // to remove any marks from 'instance' and arguments. - // Currently, "analyzability" of the callee depends on the fact that the callee - // is "accessible" through the JcApplicationGraph::callees(). - if (callee in graph.callees(callStatement)) { - - if (fact.variable.isStatic) { - return emptyList() - } + if (fact.variable.isStatic) { + return emptyList() + } - for (actual in callExpr.args) { - // Possibly tainted actual parameter: - if (fact.variable.startsWith(actual.toPathOrNull())) { - return emptyList() // Will be handled by summary edge - } + for (actual in callExpr.args) { + // Possibly tainted actual parameter: + if (fact.variable.startsWith(actual.toPathOrNull())) { + return emptyList() // Will be handled by summary edge } + } - if (callExpr is JcInstanceCallExpr) { - // Possibly tainted instance: - if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return emptyList() // Will be handled by summary edge - } + if (callExpr is JcInstanceCallExpr) { + // Possibly tainted instance: + if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { + return emptyList() // Will be handled by summary edge } - } if (callStatement is JcAssignInst) { @@ -354,7 +339,7 @@ class ForwardTaintFlowFunctions( override fun callToStart( callStatement: JcInst, calleeStart: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { val callee = calleeStart.location.method @@ -390,7 +375,7 @@ class ForwardTaintFlowFunctions( callStatement: JcInst, returnSite: JcInst, exitStatement: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { if (fact == TaintZeroFact) { return listOf(TaintZeroFact) @@ -434,7 +419,6 @@ class ForwardTaintFlowFunctions( class BackwardTaintFlowFunctions( private val project: JcClasspath, - private val graph: JcApplicationGraph, ) : FlowFunctions { override fun obtainPossibleStartFacts( method: JcMethod, @@ -480,7 +464,7 @@ class BackwardTaintFlowFunctions( override fun sequent( current: JcInst, next: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { if (fact is TaintZeroFact) { return listOf(TaintZeroFact) @@ -541,7 +525,7 @@ class BackwardTaintFlowFunctions( override fun callToReturn( callStatement: JcInst, returnSite: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { // TODO: pass-through on invokedynamic-based String concatenation @@ -552,28 +536,23 @@ class BackwardTaintFlowFunctions( val callExpr = callStatement.callExpr ?: error("Call statement should have non-null callExpr") - val callee = callExpr.method.method - if (callee in graph.callees(callStatement)) { - - if (fact.variable.isStatic) { - return emptyList() - } + if (fact.variable.isStatic) { + return emptyList() + } - for (actual in callExpr.args) { - // Possibly tainted actual parameter: - if (fact.variable.startsWith(actual.toPathOrNull())) { - return emptyList() // Will be handled by summary edge - } + for (actual in callExpr.args) { + // Possibly tainted actual parameter: + if (fact.variable.startsWith(actual.toPathOrNull())) { + return emptyList() // Will be handled by summary edge } + } - if (callExpr is JcInstanceCallExpr) { - // Possibly tainted instance: - if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return emptyList() // Will be handled by summary edge - } + if (callExpr is JcInstanceCallExpr) { + // Possibly tainted instance: + if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { + return emptyList() // Will be handled by summary edge } - } if (callStatement is JcAssignInst) { @@ -583,6 +562,7 @@ class BackwardTaintFlowFunctions( } } + // The "most default" behaviour is encapsulated here: return transmitTaintBackwardNormal(fact, callStatement) } @@ -590,7 +570,7 @@ class BackwardTaintFlowFunctions( override fun callToStart( callStatement: JcInst, calleeStart: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { val callee = calleeStart.location.method @@ -640,7 +620,7 @@ class BackwardTaintFlowFunctions( callStatement: JcInst, returnSite: JcInst, exitStatement: JcInst, - fact: TaintDomainFact + fact: TaintDomainFact, ): Collection { if (fact == TaintZeroFact) { return listOf(TaintZeroFact) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableAnalyzer.kt index 20a9b6705..3a93de0ea 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableAnalyzer.kt @@ -32,11 +32,7 @@ class UnusedVariableAnalyzer( graph, ) { override val flowFunctions by lazy { - UnusedVariableFlowFunctions(graph) - } - - private fun isExitPoint(statement: JcInst): Boolean { - return statement in graph.exitPoints(statement.location.method) + UnusedVariableFlowFunctions(graph.classpath) } override fun MutableList.onNewEdge(newEdge: Edge) { @@ -44,4 +40,8 @@ class UnusedVariableAnalyzer( add(NewSummaryEdge(selfRunnerId, newEdge)) } } + + private fun isExitPoint(statement: JcInst): Boolean { + return statement in graph.exitPoints(statement.location.method) + } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt index 6c36e897f..ef781090d 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt @@ -22,7 +22,6 @@ import org.jacodb.analysis.ifds.util.toPath import org.jacodb.analysis.ifds.util.toPathOrNull import org.jacodb.api.JcClasspath import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcInst import org.jacodb.api.cfg.JcSpecialCallExpr @@ -30,10 +29,8 @@ import org.jacodb.api.cfg.JcStaticCallExpr import org.jacodb.api.ext.cfg.callExpr class UnusedVariableFlowFunctions( - private val graph: JcApplicationGraph, + private val cp: JcClasspath, ) : FlowFunctions { - private val cp: JcClasspath - get() = graph.classpath override fun obtainPossibleStartFacts(method: JcMethod): Collection = setOf(UnusedVariableZeroFact) diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt index d4db356aa..2098df5a3 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt @@ -18,16 +18,13 @@ package org.jacodb.analysis.ifds import io.mockk.every import io.mockk.mockk -import org.jacodb.analysis.ifds.common.FlowFunctions import org.jacodb.analysis.ifds.taint.ForwardTaintFlowFunctions -import org.jacodb.analysis.ifds.taint.TaintDomainFact import org.jacodb.analysis.ifds.taint.TaintZeroFact import org.jacodb.analysis.ifds.taint.Tainted import org.jacodb.analysis.ifds.util.getArgument import org.jacodb.analysis.ifds.util.toPath import org.jacodb.api.JcClassType import org.jacodb.api.JcMethod -import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcArgument import org.jacodb.api.cfg.JcAssignInst import org.jacodb.api.cfg.JcCallExpr @@ -36,7 +33,6 @@ import org.jacodb.api.cfg.JcInst import org.jacodb.api.cfg.JcLocal import org.jacodb.api.cfg.JcLocalVar import org.jacodb.api.cfg.JcReturnInst -import org.jacodb.api.ext.cfg.callExpr import org.jacodb.api.ext.findTypeOrNull import org.jacodb.api.ext.packageName import org.jacodb.impl.features.InMemoryHierarchy @@ -63,12 +59,6 @@ class TaintFlowFunctionsTest : BaseTest() { } } - private val graph: JcApplicationGraph = mockk { - every { callees(any()) } answers { - sequenceOf(arg(0).callExpr!!.method.method) - } - } - private val stringType = cp.findTypeOrNull() as JcClassType private val testMethod = mockk { @@ -95,7 +85,7 @@ class TaintFlowFunctionsTest : BaseTest() { @Test fun `test obtain start facts`() { val flowSpace = - ForwardTaintFlowFunctions(cp, graph, configurationFeature) + ForwardTaintFlowFunctions(cp, configurationFeature) val facts = flowSpace.obtainPossibleStartFacts(testMethod).toList() val arg0 = cp.getArgument(testMethod.parameters[0])!! val arg0Taint = Tainted(arg0.toPath(), TaintMark("EXAMPLE")) @@ -108,7 +98,10 @@ class TaintFlowFunctionsTest : BaseTest() { val x: JcLocal = JcLocalVar(1, "x", stringType) val y: JcLocal = JcLocalVar(2, "y", stringType) val inst = JcAssignInst(location = mockk(), lhv = x, rhv = y) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace = ForwardTaintFlowFunctions( + cp, + configurationFeature + ) val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val facts = flowSpace.sequent(inst, next = mockk(), yTaint).toList() @@ -124,7 +117,10 @@ class TaintFlowFunctionsTest : BaseTest() { every { method } returns testMethod } }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace = ForwardTaintFlowFunctions( + cp, + configurationFeature + ) val xTaint = Tainted(x.toPath(), TaintMark("EXAMPLE")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), TaintZeroFact).toList() Assertions.assertEquals(listOf(TaintZeroFact, xTaint), facts) @@ -140,7 +136,10 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace = ForwardTaintFlowFunctions( + cp, + configurationFeature + ) val xTaint = Tainted(x.toPath(), TaintMark("REMOVE")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() Assertions.assertTrue(facts.isEmpty()) @@ -157,7 +156,10 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace = ForwardTaintFlowFunctions( + cp, + configurationFeature + ) val xTaint = Tainted(x.toPath(), TaintMark("COPY")) val yTaint = Tainted(y.toPath(), TaintMark("COPY")) val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() @@ -178,7 +180,10 @@ class TaintFlowFunctionsTest : BaseTest() { } every { args } returns listOf(x) }) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace = ForwardTaintFlowFunctions( + cp, + configurationFeature + ) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val arg0: JcArgument = cp.getArgument(testMethod.parameters[0])!! @@ -217,7 +222,10 @@ class TaintFlowFunctionsTest : BaseTest() { val exitStatement = JcReturnInst(location = mockk { every { method } returns testMethod }, returnValue = y) - val flowSpace: FlowFunctions = ForwardTaintFlowFunctions(cp, graph, configurationFeature) + val flowSpace = ForwardTaintFlowFunctions( + cp, + configurationFeature + ) val yTaint = Tainted(y.toPath(), TaintMark("TAINT")) val xTaint = Tainted(x.toPath(), TaintMark("TAINT")) val facts = flowSpace.exitToReturnSite(callStatement, returnSite = mockk(), exitStatement, yTaint).toList() From 745b509b570e219baa73671dc2a37b96f1af5c0f Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 16 May 2024 00:15:55 +0300 Subject: [PATCH 51/64] [ifds] wip: remove foojay again! --- settings.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 1a2a606f3..0fa8083b2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,7 +3,6 @@ rootProject.name = "jacodb" plugins { `gradle-enterprise` id("org.danilopianini.gradle-pre-commit-git-hooks") version "1.1.11" - id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0" } gradleEnterprise { From 30a2753b31a08059d95e3c6b8eef1350e050aa64 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 16 May 2024 11:38:23 +0300 Subject: [PATCH 52/64] [ifds] wip: CallAction --- .../jacodb/analysis/ifds/domain/CallAction.kt | 27 ++++++++++ .../analysis/ifds/domain}/FlowFunctions.kt | 7 +-- .../analysis/ifds/common/JcBaseAnalyzer.kt | 23 +++++--- .../analysis/ifds/npe/NpeFlowFunctions.kt | 41 +++++++------- .../analysis/ifds/taint/TaintFlowFunctions.kt | 54 +++++++++---------- .../unused/UnusedVariableFlowFunctions.kt | 15 ++++-- .../analysis/ifds/TaintFlowFunctionsTest.kt | 26 ++++++--- 7 files changed, 124 insertions(+), 69 deletions(-) create mode 100644 jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt rename jacodb-analysis/{taint/src/main/kotlin/org/jacodb/analysis/ifds/common => ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain}/FlowFunctions.kt (96%) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt new file mode 100644 index 000000000..b5abc50d5 --- /dev/null +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.analysis.ifds.domain + +sealed interface CallAction { + data class Return( + val fact: Fact + ) : CallAction + + data class Start( + val fact: Fact + ) : CallAction +} \ No newline at end of file diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/FlowFunctions.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt similarity index 96% rename from jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/FlowFunctions.kt rename to jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt index e4b445681..da385779c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/FlowFunctions.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt @@ -14,9 +14,10 @@ * limitations under the License. */ -package org.jacodb.analysis.ifds.common +package org.jacodb.analysis.ifds.domain interface FlowFunctions { + /** * Method for obtaining initial domain facts at the method entrypoint. * Commonly, it is only `listOf(Zero)`. @@ -51,11 +52,11 @@ interface FlowFunctions { * [ RETURN FROM p ] :: returnSite * ``` */ - fun callToReturn( + fun call( callStatement: Stmt, returnSite: Stmt, fact: Fact - ): Collection + ): Collection> /** * Call-to-start flow function. diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt index b51c0f3f9..c79e52bac 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt @@ -17,7 +17,9 @@ package org.jacodb.analysis.ifds.common import org.jacodb.analysis.ifds.domain.Analyzer +import org.jacodb.analysis.ifds.domain.CallAction import org.jacodb.analysis.ifds.domain.Edge +import org.jacodb.analysis.ifds.domain.FlowFunctions import org.jacodb.analysis.ifds.domain.Reason import org.jacodb.analysis.ifds.domain.RunnerId import org.jacodb.analysis.ifds.domain.Vertex @@ -81,22 +83,29 @@ abstract class JcBaseAnalyzer( } private fun MutableList.processCall(edge: Edge) { - val callMessage = UnresolvedCall(selfRunnerId, edge) - add(callMessage) - val reason = Reason.CallToReturn(edge) val successors = graph.successors(edge.to.statement) for (successor in successors) { - val facts = flowFunctions.callToReturn( + val actions = flowFunctions.call( callStatement = edge.to.statement, returnSite = successor, edge.to.fact ) - for (fact in facts) { - val newEdge = Edge(edge.from, Vertex(successor, fact)) - processNewEdge(selfRunnerId, newEdge, reason) + + for (action in actions) { + when (action) { + is CallAction.Return -> { + val newEdge = Edge(edge.from, Vertex(successor, action.fact)) + processNewEdge(selfRunnerId, newEdge, reason) + } + is CallAction.Start -> { + val newEdge = Edge(edge.from, Vertex(edge.to.statement, action.fact)) + val callMessage = UnresolvedCall(selfRunnerId, newEdge) + add(callMessage) + } + } } } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt index 17070d350..1a5fc83c8 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt @@ -16,7 +16,8 @@ package org.jacodb.analysis.ifds.npe -import org.jacodb.analysis.ifds.common.FlowFunctions +import org.jacodb.analysis.ifds.domain.CallAction +import org.jacodb.analysis.ifds.domain.FlowFunctions import org.jacodb.analysis.ifds.config.BasicConditionEvaluator import org.jacodb.analysis.ifds.config.CallPositionToAccessPathResolver import org.jacodb.analysis.ifds.config.CallPositionToJcValueResolver @@ -310,14 +311,14 @@ class ForwardNpeFlowFunctions( to: JcValue, ): Collection = transmitTaint(fact, at, from, to) - override fun callToReturn( + override fun call( callStatement: JcInst, returnSite: JcInst, fact: TaintDomainFact, - ): Collection { + ): Collection> { if (fact is Tainted && fact.mark == TaintMark.NULLNESS) { if (fact.variable.isDereferencedAt(callStatement)) { - return emptySet() + return listOf(CallAction.Start(fact)) } } @@ -334,30 +335,31 @@ class ForwardNpeFlowFunctions( for (arg in callExpr.args) { if (arg.toPath() == fact.variable) { return setOf( - fact, - fact.copy(variable = callStatement.lhv.toPath()) + CallAction.Return(fact), + CallAction.Return(fact.copy(variable = callStatement.lhv.toPath())) ) } } - return setOf(fact) + return setOf(CallAction.Return(fact)) } val config = taintConfigurationFeature?.getConfigForMethod(callee) if (fact == TaintZeroFact) { return buildSet { - add(TaintZeroFact) + add(CallAction.Return(TaintZeroFact)) + add(CallAction.Start(TaintZeroFact)) if (callStatement is JcAssignInst) { val toPath = callStatement.lhv.toPath() val from = callStatement.rhv if (from is JcNullConstant || (from is JcCallExpr && from.method.method.isNullable == true)) { - add(Tainted(toPath, TaintMark.NULLNESS)) + add(CallAction.Return(Tainted(toPath, TaintMark.NULLNESS))) } else if (from is JcNewArrayExpr && (from.type as JcArrayType).elementType.nullable != false) { val size = (from.type as JcArrayType).dimensions val accessors = List(size) { ElementAccessor } val path = toPath / accessors - add(Tainted(path, TaintMark.NULLNESS)) + add(CallAction.Return(Tainted(path, TaintMark.NULLNESS))) } } @@ -374,7 +376,7 @@ class ForwardNpeFlowFunctions( else -> error("$action is not supported for $item") } result.onSome { - addAll(it) + it.mapTo(this) { CallAction.Return(it) } } } } @@ -434,45 +436,40 @@ class ForwardNpeFlowFunctions( if (facts.size > 0) { logger.trace { "Got ${facts.size} facts from config for $callee: $facts" } } - return facts + return facts.map { CallAction.Return(it) } } else { // Fall back to the default behavior, as if there were no config at all. } } } - // FIXME: adhoc for constructors: - if (callee.isConstructor) { - return listOf(fact) - } - if (fact.variable.isStatic) { - return emptyList() + return listOf(CallAction.Start(fact)) } for (actual in callExpr.args) { // Possibly tainted actual parameter: if (fact.variable.startsWith(actual.toPathOrNull())) { - return emptyList() // Will be handled by summary edge + return listOf(CallAction.Start(fact)) // Will be handled by summary edge } } if (callExpr is JcInstanceCallExpr) { // Possibly tainted instance: if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return emptyList() // Will be handled by summary edge + return listOf(CallAction.Start(fact)) // Will be handled by summary edge } } if (callStatement is JcAssignInst) { // Possibly tainted lhv: if (fact.variable.startsWith(callStatement.lhv.toPathOrNull())) { - return emptyList() // Overridden by rhv + return listOf(CallAction.Start(fact)) // Overridden by rhv } } // The "most default" behaviour is encapsulated here: - return transmitTaintNormal(fact, callStatement) + return transmitTaintNormal(fact, callStatement).map { CallAction.Return(it) } } override fun callToStart( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt index a6d9955b4..1708655ed 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt @@ -16,7 +16,8 @@ package org.jacodb.analysis.ifds.taint -import org.jacodb.analysis.ifds.common.FlowFunctions +import org.jacodb.analysis.ifds.domain.CallAction +import org.jacodb.analysis.ifds.domain.FlowFunctions import org.jacodb.analysis.ifds.config.BasicConditionEvaluator import org.jacodb.analysis.ifds.config.CallPositionToAccessPathResolver import org.jacodb.analysis.ifds.config.CallPositionToJcValueResolver @@ -197,11 +198,11 @@ class ForwardTaintFlowFunctions( to: JcValue, ): Collection = transmitTaint(fact, from, to) - override fun callToReturn( + override fun call( callStatement: JcInst, returnSite: JcInst, fact: TaintDomainFact, - ): Collection { + ): Collection> { val callExpr = callStatement.callExpr ?: error("Call statement should have non-null callExpr") val callee = callExpr.method.method @@ -215,19 +216,20 @@ class ForwardTaintFlowFunctions( for (arg in callExpr.args) { if (arg.toPath() == fact.variable) { return setOf( - fact, - fact.copy(variable = callStatement.lhv.toPath()) + CallAction.Return(fact), + CallAction.Return(fact.copy(variable = callStatement.lhv.toPath())) ) } } - return setOf(fact) + return setOf(CallAction.Return(fact)) } val config = taintConfigurationFeature?.getConfigForMethod(callee) if (fact == TaintZeroFact) { return buildSet { - add(TaintZeroFact) + add(CallAction.Return(TaintZeroFact)) + add(CallAction.Start(TaintZeroFact)) if (config != null) { val conditionEvaluator = BasicConditionEvaluator(CallPositionToJcValueResolver(callStatement)) @@ -241,7 +243,10 @@ class ForwardTaintFlowFunctions( is AssignMark -> actionEvaluator.evaluate(action) else -> error("$action is not supported for $item") } - result.onSome { addAll(it) } + + result.onSome { facts -> + facts.mapTo(this) { CallAction.Return(it) } + } } } } @@ -296,44 +301,39 @@ class ForwardTaintFlowFunctions( if (facts.size > 0) { logger.trace { "Got ${facts.size} facts from config for $callee: $facts" } } - return facts + return facts.map { CallAction.Return(it) } } else { // Fall back to the default behavior, as if there were no config at all. } } - // FIXME: adhoc for constructors: - if (callee.isConstructor) { - return listOf(fact) - } - if (fact.variable.isStatic) { - return emptyList() + return listOf(CallAction.Start(fact)) } for (actual in callExpr.args) { // Possibly tainted actual parameter: if (fact.variable.startsWith(actual.toPathOrNull())) { - return emptyList() // Will be handled by summary edge + return listOf(CallAction.Start(fact)) // Will be handled by summary edge } } if (callExpr is JcInstanceCallExpr) { // Possibly tainted instance: if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return emptyList() // Will be handled by summary edge + return listOf(CallAction.Start(fact)) // Will be handled by summary edge } } if (callStatement is JcAssignInst) { // Possibly tainted lhv: if (fact.variable.startsWith(callStatement.lhv.toPathOrNull())) { - return emptyList() // Overridden by rhv + return listOf(CallAction.Start(fact)) // Overridden by rhv } } // The "most default" behaviour is encapsulated here: - return transmitTaintNormal(fact, callStatement) + return transmitTaintNormal(fact, callStatement).map { CallAction.Return(it) } } override fun callToStart( @@ -522,15 +522,15 @@ class BackwardTaintFlowFunctions( to: JcValue, ): Collection = transmitTaint(fact, from, to) - override fun callToReturn( + override fun call( callStatement: JcInst, returnSite: JcInst, fact: TaintDomainFact, - ): Collection { + ): Collection> { // TODO: pass-through on invokedynamic-based String concatenation if (fact == TaintZeroFact) { - return listOf(TaintZeroFact) + return listOf(CallAction.Start(TaintZeroFact), CallAction.Return(TaintZeroFact)) } check(fact is Tainted) @@ -538,33 +538,33 @@ class BackwardTaintFlowFunctions( ?: error("Call statement should have non-null callExpr") if (fact.variable.isStatic) { - return emptyList() + return listOf(CallAction.Start(fact)) } for (actual in callExpr.args) { // Possibly tainted actual parameter: if (fact.variable.startsWith(actual.toPathOrNull())) { - return emptyList() // Will be handled by summary edge + return listOf(CallAction.Start(fact)) // Will be handled by summary edge } } if (callExpr is JcInstanceCallExpr) { // Possibly tainted instance: if (fact.variable.startsWith(callExpr.instance.toPathOrNull())) { - return emptyList() // Will be handled by summary edge + return listOf(CallAction.Start(fact)) // Will be handled by summary edge } } if (callStatement is JcAssignInst) { // Possibly tainted rhv: if (fact.variable.startsWith(callStatement.rhv.toPathOrNull())) { - return emptyList() // Overridden by lhv + return listOf(CallAction.Start(fact)) // Overridden by lhv } } // The "most default" behaviour is encapsulated here: - return transmitTaintBackwardNormal(fact, callStatement) + return transmitTaintBackwardNormal(fact, callStatement).map { CallAction.Return(it) } } override fun callToStart( diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt index ef781090d..4e4acf13e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/UnusedVariableFlowFunctions.kt @@ -16,7 +16,8 @@ package org.jacodb.analysis.ifds.unused -import org.jacodb.analysis.ifds.common.FlowFunctions +import org.jacodb.analysis.ifds.domain.CallAction +import org.jacodb.analysis.ifds.domain.FlowFunctions import org.jacodb.analysis.ifds.util.getArgumentsOf import org.jacodb.analysis.ifds.util.toPath import org.jacodb.analysis.ifds.util.toPathOrNull @@ -70,11 +71,19 @@ class UnusedVariableFlowFunctions( return default } - override fun callToReturn( + override fun call( callStatement: JcInst, returnSite: JcInst, fact: UnusedVariableDomainFact, - ): Collection = sequent(callStatement, returnSite, fact) + ): Collection> = + sequent(callStatement, returnSite, fact) + .flatMap { newFact -> + if (newFact is UnusedVariableZeroFact) { + listOf(CallAction.Return(newFact), CallAction.Start(newFact)) + } else { + listOf(CallAction.Return(newFact)) + } + } override fun callToStart( callStatement: JcInst, diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt index 2098df5a3..d68df0083 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/TaintFlowFunctionsTest.kt @@ -18,6 +18,7 @@ package org.jacodb.analysis.ifds import io.mockk.every import io.mockk.mockk +import org.jacodb.analysis.ifds.domain.CallAction import org.jacodb.analysis.ifds.taint.ForwardTaintFlowFunctions import org.jacodb.analysis.ifds.taint.TaintZeroFact import org.jacodb.analysis.ifds.taint.Tainted @@ -122,8 +123,13 @@ class TaintFlowFunctionsTest : BaseTest() { configurationFeature ) val xTaint = Tainted(x.toPath(), TaintMark("EXAMPLE")) - val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), TaintZeroFact).toList() - Assertions.assertEquals(listOf(TaintZeroFact, xTaint), facts) + val actions = flowSpace.call(callStatement, returnSite = mockk(), TaintZeroFact).toList() + val expectedActions = listOf( + CallAction.Return(TaintZeroFact), + CallAction.Start(TaintZeroFact), + CallAction.Return(xTaint) + ) + Assertions.assertEquals(expectedActions, actions) } @Test @@ -141,7 +147,7 @@ class TaintFlowFunctionsTest : BaseTest() { configurationFeature ) val xTaint = Tainted(x.toPath(), TaintMark("REMOVE")) - val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() + val facts = flowSpace.call(callStatement, returnSite = mockk(), xTaint).toList() Assertions.assertTrue(facts.isEmpty()) } @@ -162,12 +168,18 @@ class TaintFlowFunctionsTest : BaseTest() { ) val xTaint = Tainted(x.toPath(), TaintMark("COPY")) val yTaint = Tainted(y.toPath(), TaintMark("COPY")) - val facts = flowSpace.callToReturn(callStatement, returnSite = mockk(), xTaint).toList() - Assertions.assertEquals(listOf(xTaint, yTaint), facts) // copy from x to y + val actions = flowSpace.call(callStatement, returnSite = mockk(), xTaint).toList() + val expectedActions = listOf( + CallAction.Return(xTaint), + CallAction.Return(yTaint) + ) + Assertions.assertEquals(expectedActions, actions) // copy from x to y + val other: JcLocal = JcLocalVar(10, "other", stringType) val otherTaint = Tainted(other.toPath(), TaintMark("OTHER")) - val facts2 = flowSpace.callToReturn(callStatement, returnSite = mockk(), otherTaint).toList() - Assertions.assertEquals(listOf(otherTaint), facts2) // pass-through + val actions2 = flowSpace.call(callStatement, returnSite = mockk(), otherTaint).toList() + val expectedActions2 = listOf(CallAction.Return(otherTaint)) + Assertions.assertEquals(expectedActions2, actions2) // pass-through } @Test From 90401546974187a2ebc9c3f59e842c67abbf1514 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 16 May 2024 11:41:22 +0300 Subject: [PATCH 53/64] [ifds] wip: CallAction comments --- .../jacodb/analysis/ifds/domain/CallAction.kt | 27 +++++++++++++++++++ .../analysis/ifds/domain/FlowFunctions.kt | 10 +------ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt index b5abc50d5..e3a9c7aa4 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt @@ -17,10 +17,37 @@ package org.jacodb.analysis.ifds.domain sealed interface CallAction { + /** + * Call-to-return-site action. + * + * ``` + * [ CALL p ] :: callStatement + * : + * : (call-to-return-site edge) + * : + * [ RETURN FROM p ] :: returnSite + * ``` + */ data class Return( val fact: Fact ) : CallAction + /** + * Call-to-start action. + * + * ``` + * [ CALL p ] :: callStatement + * : \ + * : \ (call-to-start edge) + * : \ + * : [ START p ] :: calleeStart + * : | + * : [ EXIT p ] + * : / + * : / + * [ RETURN FROM p ] + * ``` + */ data class Start( val fact: Fact ) : CallAction diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt index da385779c..29451ab02 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt @@ -42,15 +42,7 @@ interface FlowFunctions { ): Collection /** - * Call-to-return-site flow function. - * - * ``` - * [ CALL p ] :: callStatement - * : - * : (call-to-return-site edge) - * : - * [ RETURN FROM p ] :: returnSite - * ``` + * Call flow function. */ fun call( callStatement: Stmt, From c433868c1cded0cf3256c2b5c8749480d0a43e70 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 16 May 2024 12:13:49 +0300 Subject: [PATCH 54/64] [ifds] wip: add some tests --- jacodb-analysis/actors/build.gradle.kts | 1 + .../jacodb/actors/api/options/SpawnOptions.kt | 9 -- .../jacodb/actors/impl/ActorContextImpl.kt | 4 +- .../jacodb/actors/impl/ActorSpawnerImpl.kt | 2 +- .../jacodb/actors/impl/routing/Builders.kt | 4 +- .../actors/impl/routing/RandomRouter.kt | 4 +- .../jacodb/actors/impl/workers/ActorWorker.kt | 1 - .../impl/workers/InternalActorWorker.kt | 4 +- .../actors/impl/workers/UserActorWorker.kt | 2 +- .../kotlin/org/jacodb/actors/RoutersTest.kt | 123 ++++++++++++++++++ .../kotlin/org/jacodb/actors/StoppingTest.kt | 2 +- .../analysis/ifds/JavaAnalysisApiTest.java | 8 ++ 12 files changed, 144 insertions(+), 20 deletions(-) create mode 100644 jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/RoutersTest.kt diff --git a/jacodb-analysis/actors/build.gradle.kts b/jacodb-analysis/actors/build.gradle.kts index 2386bc53c..998fa8943 100644 --- a/jacodb-analysis/actors/build.gradle.kts +++ b/jacodb-analysis/actors/build.gradle.kts @@ -4,4 +4,5 @@ dependencies { implementation(Libs.kotlinx_coroutines_core) testImplementation(kotlin("test")) + testImplementation(Libs.mockk) } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt index f9b4c0c47..a1c55b2b5 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt @@ -22,27 +22,18 @@ import kotlin.coroutines.EmptyCoroutineContext class SpawnOptions( val channelFactory: ChannelFactory, - val coroutineContext: CoroutineContext, ) { fun channelFactory(channelFactory: ChannelFactory) = SpawnOptions( channelFactory = channelFactory, - coroutineContext = coroutineContext ) fun channel(channel: Channel) = SpawnOptions( channelFactory = { channel }, - coroutineContext = coroutineContext - ) - - fun coroutineContext(coroutineContext: CoroutineContext) = SpawnOptions( - channelFactory = channelFactory, - coroutineContext = coroutineContext ) companion object { val default = SpawnOptions( ChannelFactory.unlimited(), - EmptyCoroutineContext ) } } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt index f57e3eed4..8c752e516 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt @@ -22,7 +22,6 @@ import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorSpawner import org.jacodb.actors.impl.workers.ActorWorker -import kotlin.coroutines.CoroutineContext internal class ActorContextImpl( private val spawner: ActorSpawner, @@ -34,11 +33,10 @@ internal class ActorContextImpl( get() = worker fun launch( - coroutineContext: CoroutineContext, actorFactory: ActorFactory, ) { val actor = actorFactory.run { create() } - worker.launchLoop(coroutineContext, actor) + worker.launchLoop(actor) } override suspend fun ActorRef.send(message: TargetMessage) { diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt index be060ce60..19e70d41e 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSpawnerImpl.kt @@ -72,7 +72,7 @@ internal class ActorSpawnerImpl( val worker = workerFactory(path, channel, system) val context = ActorContextImpl(spawner, worker, logger(path.toString())) - context.launch(options.coroutineContext, actorFactory) + context.launch(actorFactory) children[name] = context return worker diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt index 63be407a3..410a8950c 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt @@ -18,6 +18,7 @@ package org.jacodb.actors.impl.routing import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.options.SpawnOptions +import kotlin.random.Random fun roundRobinRouter( size: Int = 8, @@ -29,10 +30,11 @@ fun roundRobinRouter( fun randomRouter( size: Int = 8, + random: Random = Random, routeeSpawnOptions: SpawnOptions = SpawnOptions.default, routeeFactory: ActorFactory, ) = ActorFactory { - RandomRouter(size, routeeSpawnOptions, routeeFactory) + RandomRouter(size, random, routeeSpawnOptions, routeeFactory) } fun messageKeyRouter( diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt index 4bf00b0b8..ad3572c69 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/RandomRouter.kt @@ -20,10 +20,12 @@ import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.options.SpawnOptions +import kotlin.random.Random context(ActorContext) internal class RandomRouter( size: Int, + private val random: Random, routeeSpawnOptions: SpawnOptions, routeeFactory: ActorFactory, ) : Actor { @@ -32,6 +34,6 @@ internal class RandomRouter( } override suspend fun receive(message: Message) { - routees.random().send(message) + routees.random(random).send(message) } } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt index 0b9d9f845..580678074 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt @@ -30,7 +30,6 @@ internal abstract class ActorWorker( path: ActorPath, ) : ActorRef(path) { abstract fun launchLoop( - coroutineContext: CoroutineContext, actor: Actor, ) diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt index 0feb78a59..dbf41ae4f 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt @@ -30,8 +30,8 @@ internal class InternalActorWorker( private val scope: CoroutineScope, ) : ActorWorker(path) { - override fun launchLoop(coroutineContext: CoroutineContext, actor: Actor) { - scope.launch(coroutineContext) { + override fun launchLoop(actor: Actor) { + scope.launch { loop(actor) } } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt index cf8739417..e4fe98b26 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt @@ -43,7 +43,7 @@ internal class UserActorWorker( private var status = ActorStatus.BUSY private val working = AtomicBoolean(true) - override fun launchLoop(coroutineContext: CoroutineContext, actor: Actor) { + override fun launchLoop(actor: Actor) { scope.launch { sendInternal(watcher, WatcherMessage.Register(path)) actor.receive(Signal.Start) diff --git a/jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/RoutersTest.kt b/jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/RoutersTest.kt new file mode 100644 index 000000000..c02a25d42 --- /dev/null +++ b/jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/RoutersTest.kt @@ -0,0 +1,123 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors + +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking +import org.jacodb.actors.api.Actor +import org.jacodb.actors.api.ActorContext +import org.jacodb.actors.impl.routing.messageKeyRouter +import org.jacodb.actors.impl.routing.randomRouter +import org.jacodb.actors.impl.routing.roundRobinRouter +import org.jacodb.actors.impl.system +import java.util.concurrent.ConcurrentLinkedDeque +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.time.Duration.Companion.milliseconds + +class RoutersTest { + private val log = ConcurrentLinkedDeque>() + + context(ActorContext) + class Logger( + private val selfId: Int, + private val log: ConcurrentLinkedDeque>, + ) : Actor { + override suspend fun receive(message: Int) { + log.add(selfId to message) + } + } + + @Test + fun `Test message key router`() = runBlocking { + val system = system( + "test", + actorFactory = messageKeyRouter(keyExtractor = { a -> a % 4 }) { + Logger(it, log) + } + ) + + + repeat(12) { msg -> + delay(20.milliseconds) + system.send(msg) + } + + system.awaitCompletion() + + val expectedLog = List(12) { (it % 4) to it } + assertEquals(expectedLog, log.toList()) + } + + @Test + fun `Test round robin router`() = runBlocking { + val size = 4 + + var idx = 0 + + val system = system( + "test", + actorFactory = roundRobinRouter(size = size) { + Logger(idx++, log) + } + ) + + + repeat(12) { msg -> + delay(20.milliseconds) + system.send(msg) + } + + system.awaitCompletion() + + val expectedLog = List(12) { (it % size) to it } + assertEquals(expectedLog, log.toList()) + } + + @Test + fun `Test random router`() = runBlocking { + val size = 4 + val randomSequence = listOf(2, 2, 8, 1, 3, 3, 7, 6).map { it % size } + + val random = mockk { + every { nextInt(any()) } returnsMany randomSequence + } + + var idx = 0 + + val system = system( + "test", + actorFactory = randomRouter(size = size, random = random) { + Logger(idx++, log) + } + ) + + + repeat(randomSequence.size) { msg -> + delay(20.milliseconds) + system.send(msg) + } + + system.awaitCompletion() + + val expectedLog = randomSequence.withIndex().map { (it.value % size) to it.index } + assertEquals(expectedLog, log.toList()) + } +} \ No newline at end of file diff --git a/jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt b/jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt index 77cbdf004..328be962b 100644 --- a/jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt +++ b/jacodb-analysis/actors/src/test/kotlin/org/jacodb/actors/StoppingTest.kt @@ -50,7 +50,7 @@ class StoppingTest { } @Test - fun testStops() = runBlocking { + fun `Test stops`() = runBlocking { val system = system("test") { Repeater(null, 2) } system.send(0) diff --git a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java index f794ad9e1..677ca4324 100644 --- a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java +++ b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java @@ -73,5 +73,13 @@ public void testJavaAnalysisApi() throws ExecutionException, InterruptedExceptio methodsToAnalyze, toDuration(30, DurationUnit.SECONDS)) .get(); + + ifds.startAnalysis(methodsToAnalyze.get(0)).get(); + + ifds.awaitAnalysis().get(); + + ifds.collectComputationData().get(); + + ifds.collectFindings().get(); } } From d213980d20188843386bb97557096f2ceda67bf9 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 16 May 2024 12:17:05 +0300 Subject: [PATCH 55/64] [ifds] wip: minor --- .../kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt | 3 +-- .../kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt index a76f2bda1..5c7c0cc7c 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt @@ -36,7 +36,7 @@ class ChunkManager( private val routerFactory = messageKeyRouter( ifdsContext::runnerIdByMessage ) { runnerId -> - org.jacodb.analysis.ifds.actors.Runner(this@ActorContext.self, ifdsContext, chunk, runnerId) + Runner(this@ActorContext.self, ifdsContext, chunk, runnerId) } private val router = spawn( @@ -59,7 +59,6 @@ class ChunkManager( } Signal.PostStop -> { - // TODO: explain why we do nothing here // do nothing } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt index 99d1e8dbe..ec997acef 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt @@ -37,7 +37,7 @@ class ProjectManager( private val routerFactory = messageKeyRouter( keyExtractor = ifdsContext::chunkByMessage - ) { chunk -> org.jacodb.analysis.ifds.actors.ChunkManager(ifdsContext, chunk, this@ActorContext.self) } + ) { chunk -> ChunkManager(ifdsContext, chunk, this@ActorContext.self) } private val router = spawn("chunks", actorFactory = routerFactory) From 5d489fe1626d753250c4823b761372ea80431815 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 16 May 2024 12:18:14 +0300 Subject: [PATCH 56/64] [ifds] wip: exception --- .../main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt index 5c7c0cc7c..32f3c4e42 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt @@ -63,7 +63,7 @@ class ChunkManager( } is Signal.Exception -> { - logger.error { signal.exception.stackTraceToString() } + logger.error(signal.exception) { "Catch exception in chunk manager:" } } } } From 59920892aea758135529d73394618412a3dcd219 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 16 May 2024 13:45:17 +0300 Subject: [PATCH 57/64] [ifds] wip: add statistics every 10 seconds + options --- .../org/jacodb/actors/api/ActorContext.kt | 3 ++ .../jacodb/actors/impl/ActorContextImpl.kt | 5 +++ .../org/jacodb/actors/impl/ActorSystemImpl.kt | 19 ++++++---- .../jacodb/actors/impl/ActorSystemOptions.kt | 23 ++++++++++++ .../actors/{ => internal}/WatcherActor.kt | 37 ++++++++++++++++--- .../actors/{ => internal}/WatcherMessages.kt | 4 +- .../jacodb/actors/impl/workers/ActorWorker.kt | 7 +++- .../impl/workers/InternalActorWorker.kt | 13 ++++++- .../actors/impl/workers/UserActorWorker.kt | 15 ++++++-- .../analysis/graph/JcApplicationGraphImpl.kt | 2 +- .../org/jacodb/analysis/ifds/IfdsContext.kt | 2 + .../jacodb/analysis/ifds/IfdsSystemOptions.kt | 21 +++++++++++ .../analysis/ifds/actors/ChunkManager.kt | 3 +- .../analysis/ifds/actors/ProjectManager.kt | 3 +- .../org/jacodb/analysis/ifds/actors/Runner.kt | 7 ++-- .../analysis/ifds/common/JcChunkResolver.kt | 5 +-- .../analysis/ifds/common/JcIfdsContext.kt | 8 +++- .../analysis/ifds/common/JcIfdsFacade.kt | 13 ++++++- .../org/jacodb/analysis/ifds/npe/Builders.kt | 23 +++++++----- .../jacodb/analysis/ifds/taint/Builders.kt | 23 +++++++----- .../jacodb/analysis/ifds/unused/Builders.kt | 23 +++++++----- .../analysis/ifds/JavaAnalysisApiTest.java | 1 + .../org/jacodb/analysis/ifds/IfdsSqlTest.kt | 2 +- .../jacodb/analysis/ifds/IfdsUnusedTest.kt | 2 +- .../analysis/ifds/JodaDateTimeAnalysisTest.kt | 6 +-- 25 files changed, 205 insertions(+), 65 deletions(-) create mode 100644 jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemOptions.kt rename jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/{ => internal}/WatcherActor.kt (71%) rename jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/{ => internal}/WatcherMessages.kt (93%) create mode 100644 jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsSystemOptions.kt diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt index c9e254b72..9e6e258a9 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorContext.kt @@ -17,12 +17,15 @@ package org.jacodb.actors.api import mu.KLogger +import kotlin.time.Duration interface ActorContext : ActorSpawner { val self: ActorRef suspend fun ActorRef.send(message: TargetMessage) + suspend fun sendSelfWithDelay(message: M, waitDelay: Duration) + fun stop() fun resume() diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt index 8c752e516..4e12810b5 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorContextImpl.kt @@ -22,6 +22,7 @@ import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorSpawner import org.jacodb.actors.impl.workers.ActorWorker +import kotlin.time.Duration internal class ActorContextImpl( private val spawner: ActorSpawner, @@ -43,6 +44,10 @@ internal class ActorContextImpl( worker.send(this, message) } + override suspend fun sendSelfWithDelay(message: Message, waitDelay: Duration) { + worker.sendSelfWithDelay(message, waitDelay) + } + override fun stop() { worker.stop() for ((name, _) in children()) { diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 4233f549f..781aee301 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -25,12 +25,13 @@ import mu.KotlinLogging.logger import org.jacodb.actors.api.ActorFactory import org.jacodb.actors.api.ActorSystem import org.jacodb.actors.api.options.SpawnOptions -import org.jacodb.actors.impl.actors.WatcherActor -import org.jacodb.actors.impl.actors.WatcherMessage +import org.jacodb.actors.impl.actors.internal.WatcherActor +import org.jacodb.actors.impl.actors.internal.WatcherMessage internal class ActorSystemImpl( override val name: String, - options: SpawnOptions, + systemOptions: ActorSystemOptions, + spawnOptions: SpawnOptions, actorFactory: ActorFactory, ) : ActorSystem, AutoCloseable { private val path = root() / name @@ -41,9 +42,11 @@ internal class ActorSystemImpl( internal val scope = CoroutineScope(Job()) - internal val watcher = spawner.spawnInternalActor(WATCHER_ACTOR_NAME, SpawnOptions.default, ::WatcherActor) + internal val watcher = spawner.spawnInternalActor(WATCHER_ACTOR_NAME, SpawnOptions.default) { + WatcherActor(systemOptions.printStatisticsPeriod) + } - private val user = spawner.spawn(USER_ACTOR_NAME, options, actorFactory) + private val user = spawner.spawn(USER_ACTOR_NAME, spawnOptions, actorFactory) override suspend fun send(message: Message) { watcher.receive(WatcherMessage.OutOfSystemSend) @@ -86,10 +89,12 @@ internal class ActorSystemImpl( fun system( name: String, - options: SpawnOptions = SpawnOptions.default, + systemOptions: ActorSystemOptions = ActorSystemOptions(), + spawnOptions: SpawnOptions = SpawnOptions.default, actorFactory: ActorFactory, ): ActorSystem = ActorSystemImpl( name, - options, + systemOptions, + spawnOptions, actorFactory ) diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemOptions.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemOptions.kt new file mode 100644 index 000000000..f53bcd189 --- /dev/null +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemOptions.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.actors.impl + +import kotlin.time.Duration + +data class ActorSystemOptions( + val printStatisticsPeriod: Duration? = null, +) \ No newline at end of file diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/internal/WatcherActor.kt similarity index 71% rename from jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/internal/WatcherActor.kt index 462e2ff75..a2268d53f 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherActor.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/internal/WatcherActor.kt @@ -14,16 +14,20 @@ * limitations under the License. */ -package org.jacodb.actors.impl.actors +package org.jacodb.actors.impl.actors.internal import kotlinx.coroutines.CompletableDeferred import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorStatus +import org.jacodb.actors.api.signal.Signal +import kotlin.time.Duration context(ActorContext) -internal class WatcherActor : Actor { +internal class WatcherActor( + private val printStatisticsPeriod: Duration? = null, +) : Actor { private sealed interface Status { data object Idle : Status data class DetectingTermination( @@ -46,6 +50,14 @@ internal class WatcherActor : Actor { totalReceived = 0 ) + override suspend fun receive(signal: Signal) { + if (signal == Signal.Start) { + if (printStatisticsPeriod != null) { + sendSelfWithDelay(WatcherMessage.Print, printStatisticsPeriod) + } + } + } + override suspend fun receive(message: WatcherMessage) { when (message) { WatcherMessage.Idle -> { @@ -67,6 +79,13 @@ internal class WatcherActor : Actor { is WatcherMessage.UpdateSnapshot -> { updateSnapshot(message.path, message.snapshot) } + + WatcherMessage.Print -> { + if (!isTerminated()) { + printStatistics() + sendSelfWithDelay(WatcherMessage.Print, printStatisticsPeriod!!) + } + } } val status = state.status if (status is Status.DetectingTermination) { @@ -74,15 +93,23 @@ internal class WatcherActor : Actor { } } + private fun printStatistics() { + logger.info { "Actors: ${state.terminatedActors}/${watchList.size}" } + val percent = 100.0 * state.totalReceived / state.totalSent + val left = state.totalSent - state.totalReceived + logger.info { "Messages: ${state.totalReceived}/${state.totalSent}\t${"%.2f".format(percent)}%\tLeft: $left" } + } + private fun checkTermination(computationFinished: CompletableDeferred) { - if (state.terminatedActors == watchList.size && state.totalSent == state.totalReceived) { - logger.info { "Actors: ${state.terminatedActors}/${watchList.size}" } - logger.info { "Messages: ${state.totalReceived}/${state.totalSent}" } + if (isTerminated()) { + printStatistics() logger.info { "Computation finished..." } computationFinished.complete(Unit) } } + private fun isTerminated() = state.terminatedActors == watchList.size && state.totalSent == state.totalReceived + private fun updateSnapshot(path: ActorPath, newSnapshot: Snapshot) { val currentSnapshot = watchList[path] ?: error("$this can't find the current snapshot of $path") diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/internal/WatcherMessages.kt similarity index 93% rename from jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt rename to jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/internal/WatcherMessages.kt index cabb8d775..045bee5c0 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/WatcherMessages.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/internal/WatcherMessages.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jacodb.actors.impl.actors +package org.jacodb.actors.impl.actors.internal import kotlinx.coroutines.CompletableDeferred import org.jacodb.actors.api.ActorPath @@ -44,4 +44,6 @@ internal sealed interface WatcherMessage { data class AwaitTermination( val computationFinished: CompletableDeferred, ) : WatcherMessage + + data object Print : WatcherMessage } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt index 580678074..4852eefe3 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/ActorWorker.kt @@ -21,7 +21,7 @@ import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef import org.jacodb.actors.impl.ActorSystemImpl -import kotlin.coroutines.CoroutineContext +import kotlin.time.Duration internal typealias WorkerFactory = (ActorPath, Channel, ActorSystemImpl<*>) -> ActorWorker @@ -40,4 +40,9 @@ internal abstract class ActorWorker( destination: ActorRef, message: TargetMessage, ) + + abstract fun sendSelfWithDelay( + message: Message, + waitDelay: Duration, + ) } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt index dbf41ae4f..e34f1b809 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/InternalActorWorker.kt @@ -18,11 +18,13 @@ package org.jacodb.actors.impl.workers import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef -import kotlin.coroutines.CoroutineContext +import org.jacodb.actors.api.signal.Signal +import kotlin.time.Duration internal class InternalActorWorker( path: ActorPath, @@ -46,6 +48,13 @@ internal class InternalActorWorker( destination.receive(message) } + override fun sendSelfWithDelay(message: Message, waitDelay: Duration) { + scope.launch { + delay(waitDelay) + receive(message) + } + } + override suspend fun receive(message: Message): Boolean { channel.send(message) return true @@ -54,8 +63,10 @@ internal class InternalActorWorker( private suspend fun loop( actor: Actor, ) { + actor.receive(Signal.Start) for (message in channel) { actor.receive(message) } + actor.receive(Signal.PostStop) } } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt index e4fe98b26..b0a611546 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/workers/UserActorWorker.kt @@ -20,16 +20,17 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.onClosed import kotlinx.coroutines.channels.onSuccess +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorPath import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.ActorStatus import org.jacodb.actors.api.signal.Signal -import org.jacodb.actors.impl.actors.Snapshot -import org.jacodb.actors.impl.actors.WatcherMessage +import org.jacodb.actors.impl.actors.internal.Snapshot +import org.jacodb.actors.impl.actors.internal.WatcherMessage import java.util.concurrent.atomic.AtomicBoolean -import kotlin.coroutines.CoroutineContext +import kotlin.time.Duration internal class UserActorWorker( path: ActorPath, @@ -58,6 +59,14 @@ internal class UserActorWorker( } } + override fun sendSelfWithDelay(message: Message, waitDelay: Duration) { + sent++ + scope.launch { + delay(waitDelay) + receive(message) + } + } + override suspend fun receive(message: Message): Boolean { channel.send(message) return true diff --git a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt index ed5dbffc4..275c6ab94 100644 --- a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/graph/JcApplicationGraphImpl.kt @@ -31,7 +31,7 @@ import java.util.concurrent.CompletableFuture /** * Possible we will need JcRawInst instead of JcInst */ -open class JcApplicationGraphImpl( +class JcApplicationGraphImpl( override val classpath: JcClasspath, private val usages: SyncUsagesExtension, ) : JcApplicationGraph { diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt index df09fc5b2..87d6251f2 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt @@ -23,6 +23,8 @@ import org.jacodb.analysis.ifds.domain.RunnerId import org.jacodb.analysis.ifds.messages.RunnerMessage interface IfdsContext { + val options: IfdsSystemOptions + fun chunkByMessage(message: RunnerMessage): Chunk fun runnerIdByMessage(message: RunnerMessage): RunnerId diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsSystemOptions.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsSystemOptions.kt new file mode 100644 index 000000000..7bcd00076 --- /dev/null +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsSystemOptions.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.analysis.ifds + +data class IfdsSystemOptions( + val workersPerRunner: Int = 8, +) \ No newline at end of file diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt index 32f3c4e42..e9a32751a 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ChunkManager.kt @@ -21,6 +21,7 @@ import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.actors.api.signal.Signal import org.jacodb.actors.impl.routing.messageKeyRouter +import org.jacodb.analysis.ifds.IfdsContext import org.jacodb.analysis.ifds.domain.Chunk import org.jacodb.analysis.ifds.messages.CommonMessage import org.jacodb.analysis.ifds.messages.NewChunk @@ -28,7 +29,7 @@ import org.jacodb.analysis.ifds.messages.RunnerMessage context(ActorContext) class ChunkManager( - private val ifdsContext: org.jacodb.analysis.ifds.IfdsContext, + private val ifdsContext: IfdsContext, private val chunk: Chunk, private val parent: ActorRef, ) : Actor { diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt index ec997acef..fc5d66c8b 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/ProjectManager.kt @@ -20,6 +20,7 @@ import kotlinx.coroutines.CompletableDeferred import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.impl.routing.messageKeyRouter +import org.jacodb.analysis.ifds.IfdsContext import org.jacodb.analysis.ifds.domain.Chunk import org.jacodb.analysis.ifds.messages.CollectAllData import org.jacodb.analysis.ifds.messages.CollectData @@ -32,7 +33,7 @@ import org.jacodb.analysis.ifds.result.IfdsComputationData context(ActorContext) class ProjectManager( - private val ifdsContext: org.jacodb.analysis.ifds.IfdsContext, + private val ifdsContext: IfdsContext, ) : Actor { private val routerFactory = messageKeyRouter( diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt index 0dd446163..7f1462702 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt @@ -20,6 +20,7 @@ import org.jacodb.actors.api.Actor import org.jacodb.actors.api.ActorContext import org.jacodb.actors.api.ActorRef import org.jacodb.actors.impl.routing.roundRobinRouter +import org.jacodb.analysis.ifds.IfdsContext import org.jacodb.analysis.ifds.domain.Analyzer import org.jacodb.analysis.ifds.domain.Chunk import org.jacodb.analysis.ifds.domain.RunnerId @@ -31,14 +32,14 @@ import org.jacodb.analysis.ifds.messages.StorageMessage context(ActorContext) class Runner( private val parent: ActorRef, - private val ifdsContext: org.jacodb.analysis.ifds.IfdsContext, + private val ifdsContext: IfdsContext, private val chunk: Chunk, private val runnerId: RunnerId, ) : Actor { - private val routerFactory = roundRobinRouter(size = 8) { + private val routerFactory = roundRobinRouter(size = ifdsContext.options.workersPerRunner) { @Suppress("UNCHECKED_CAST") val analyzer = ifdsContext.getAnalyzer(runnerId) as Analyzer - Worker(analyzer, this@ActorContext.self) + Worker(analyzer, this@ActorContext.self) } private val router = spawn("workers", actorFactory = routerFactory) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt index 4c704bca2..72325add9 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt @@ -16,6 +16,7 @@ package org.jacodb.analysis.ifds.common +import org.jacodb.analysis.ifds.ChunkResolver import org.jacodb.analysis.ifds.domain.Chunk import org.jacodb.analysis.ifds.messages.AnalyzerMessage import org.jacodb.analysis.ifds.messages.CollectData @@ -33,13 +34,11 @@ import org.jacodb.analysis.ifds.messages.StorageMessage import org.jacodb.analysis.ifds.messages.SubscriptionOnEnd import org.jacodb.analysis.ifds.messages.SubscriptionOnStart import org.jacodb.analysis.ifds.messages.UnresolvedCall -import org.jacodb.api.analysis.JcApplicationGraph import org.jacodb.api.cfg.JcInst class JcChunkResolver( - private val graph: JcApplicationGraph, private val chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy, -) : org.jacodb.analysis.ifds.ChunkResolver { +) : ChunkResolver { @Suppress("UNCHECKED_CAST") override fun chunkByMessage(message: RunnerMessage): Chunk = when (message) { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt index 0c136af6b..30b7ca81c 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt @@ -16,6 +16,9 @@ package org.jacodb.analysis.ifds.common +import org.jacodb.analysis.ifds.ChunkResolver +import org.jacodb.analysis.ifds.IfdsContext +import org.jacodb.analysis.ifds.IfdsSystemOptions import org.jacodb.analysis.ifds.domain.Chunk import org.jacodb.analysis.ifds.domain.IndirectionHandler import org.jacodb.analysis.ifds.domain.RunnerId @@ -27,10 +30,11 @@ import java.util.concurrent.ConcurrentHashMap class JcIfdsContext( private val cp: JcClasspath, + override val options: IfdsSystemOptions, private val bannedPackagePrefixes: List, - private val chunkStrategy: org.jacodb.analysis.ifds.ChunkResolver, + private val chunkStrategy: ChunkResolver, private val analyzerFactory: (RunnerId) -> JcBaseAnalyzer, -) : org.jacodb.analysis.ifds.IfdsContext { +) : IfdsContext { override fun chunkByMessage(message: RunnerMessage): Chunk = chunkStrategy.chunkByMessage(message) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt index b63f188ee..6101208c2 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt @@ -20,6 +20,9 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.jacodb.actors.api.ActorSystem +import org.jacodb.actors.impl.ActorSystemOptions +import org.jacodb.actors.impl.system +import org.jacodb.analysis.ifds.actors.ProjectManager import org.jacodb.analysis.ifds.domain.Edge import org.jacodb.analysis.ifds.domain.Reason import org.jacodb.analysis.ifds.domain.RunnerId @@ -37,11 +40,15 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds open class JcIfdsFacade>( + name: String, private val graph: JcApplicationGraph, private val context: JcIfdsContext, - private val system: ActorSystem, private val startingRunnerId: RunnerId, ) : AutoCloseable { + private val system: ActorSystem = system(name, DefaultSystemOptions) { + ProjectManager(context) + } + open suspend fun runAnalysis( methods: Collection, timeout: Duration = 60.seconds, @@ -92,4 +99,8 @@ open class JcIfdsFacade>( override fun close() { system.close() } + + companion object { + val DefaultSystemOptions = ActorSystemOptions(printStatisticsPeriod = 10.seconds) + } } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt index 706598dc6..9335dd79e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt @@ -16,8 +16,8 @@ package org.jacodb.analysis.ifds.npe -import org.jacodb.actors.impl.system -import org.jacodb.analysis.ifds.actors.ProjectManager +import org.jacodb.analysis.ifds.ChunkStrategy +import org.jacodb.analysis.ifds.IfdsSystemOptions import org.jacodb.analysis.ifds.common.ClassChunkStrategy import org.jacodb.analysis.ifds.common.JcAsyncIfdsFacade import org.jacodb.analysis.ifds.common.JcChunkResolver @@ -33,13 +33,15 @@ import org.jacodb.api.cfg.JcInst fun npeIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, + ifdsSystemOptions: IfdsSystemOptions = IfdsSystemOptions(), bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsContext = JcIfdsContext( cp, + ifdsSystemOptions, bannedPackagePrefixes, - JcChunkResolver(graph, chunkStrategy) + JcChunkResolver(chunkStrategy) ) { runnerId -> val analyzer = when (runnerId) { is SingletonRunnerId -> NpeAnalyzer(runnerId, graph) @@ -53,21 +55,22 @@ fun npeIfdsFacade( name: String, cp: JcClasspath, graph: JcApplicationGraph, + ifdsSystemOptions: IfdsSystemOptions = IfdsSystemOptions(), bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsFacade { - val context = npeIfdsContext(cp, graph, bannedPackagePrefixes, chunkStrategy) - val system = system(name) { ProjectManager(context) } - return JcIfdsFacade(graph, context, system, SingletonRunnerId) + val context = npeIfdsContext(cp, graph, ifdsSystemOptions, bannedPackagePrefixes, chunkStrategy) + return JcIfdsFacade(name, graph, context, SingletonRunnerId) } fun asyncNpeIfdsFacade( name: String, cp: JcClasspath, graph: JcApplicationGraph, + ifdsSystemOptions: IfdsSystemOptions = IfdsSystemOptions(), bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcAsyncIfdsFacade { - val facade = npeIfdsFacade(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + val facade = npeIfdsFacade(name, cp, graph, ifdsSystemOptions, bannedPackagePrefixes, chunkStrategy) return JcAsyncIfdsFacade(facade) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt index 54f57ffd5..49d12842a 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt @@ -16,8 +16,8 @@ package org.jacodb.analysis.ifds.taint -import org.jacodb.actors.impl.system -import org.jacodb.analysis.ifds.actors.ProjectManager +import org.jacodb.analysis.ifds.ChunkStrategy +import org.jacodb.analysis.ifds.IfdsSystemOptions import org.jacodb.analysis.ifds.common.BackwardRunnerId import org.jacodb.analysis.ifds.common.ClassChunkStrategy import org.jacodb.analysis.ifds.common.ForwardRunnerId @@ -33,13 +33,15 @@ import org.jacodb.api.cfg.JcInst fun taintIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, + ifdsSystemOptions: IfdsSystemOptions = IfdsSystemOptions(), bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsContext = JcIfdsContext( cp, + ifdsSystemOptions, bannedPackagePrefixes, - JcChunkResolver(graph, chunkStrategy) + JcChunkResolver(chunkStrategy) ) { runnerId -> when (runnerId) { is ForwardRunnerId -> ForwardTaintAnalyzer(ForwardRunnerId, graph) @@ -52,21 +54,22 @@ fun taintIfdsFacade( name: String, cp: JcClasspath, graph: JcApplicationGraph, + ifdsSystemOptions: IfdsSystemOptions = IfdsSystemOptions(), bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsFacade { - val context = taintIfdsContext(cp, graph, bannedPackagePrefixes, chunkStrategy) - val system = system(name) { ProjectManager(context) } - return JcIfdsFacade(graph, context, system, ForwardRunnerId) + val context = taintIfdsContext(cp, graph, ifdsSystemOptions, bannedPackagePrefixes, chunkStrategy) + return JcIfdsFacade(name, graph, context, ForwardRunnerId) } fun asyncTaintIfdsFacade( name: String, cp: JcClasspath, graph: JcApplicationGraph, + ifdsSystemOptions: IfdsSystemOptions = IfdsSystemOptions(), bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcAsyncIfdsFacade { - val facade = taintIfdsFacade(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + val facade = taintIfdsFacade(name, cp, graph, ifdsSystemOptions, bannedPackagePrefixes, chunkStrategy) return JcAsyncIfdsFacade(facade) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt index 292e5699f..77dc57f3e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt @@ -16,8 +16,8 @@ package org.jacodb.analysis.ifds.unused -import org.jacodb.actors.impl.system -import org.jacodb.analysis.ifds.actors.ProjectManager +import org.jacodb.analysis.ifds.ChunkStrategy +import org.jacodb.analysis.ifds.IfdsSystemOptions import org.jacodb.analysis.ifds.common.ClassChunkStrategy import org.jacodb.analysis.ifds.common.JcAsyncIfdsFacade import org.jacodb.analysis.ifds.common.JcChunkResolver @@ -33,13 +33,15 @@ import org.jacodb.api.cfg.JcInst fun unusedIfdsContext( cp: JcClasspath, graph: JcApplicationGraph, + ifdsSystemOptions: IfdsSystemOptions = IfdsSystemOptions(), bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsContext = JcIfdsContext( cp, + ifdsSystemOptions, bannedPackagePrefixes, - JcChunkResolver(graph, chunkStrategy) + JcChunkResolver(chunkStrategy) ) { runnerId -> when (runnerId) { is SingletonRunnerId -> UnusedVariableAnalyzer(SingletonRunnerId, graph) @@ -51,15 +53,15 @@ fun unusedIfdsFacade( name: String, cp: JcClasspath, graph: JcApplicationGraph, + ifdsSystemOptions: IfdsSystemOptions = IfdsSystemOptions(), bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcIfdsFacade { - val context = unusedIfdsContext(cp, graph, bannedPackagePrefixes, chunkStrategy) - val system = system(name) { ProjectManager(context) } + val context = unusedIfdsContext(cp, graph, ifdsSystemOptions, bannedPackagePrefixes, chunkStrategy) return object : JcIfdsFacade( + name, graph, context, - system, SingletonRunnerId ) { override suspend fun collectFindings(): Collection { @@ -94,9 +96,10 @@ fun asyncUnusedIfdsFacade( name: String, cp: JcClasspath, graph: JcApplicationGraph, + ifdsSystemOptions: IfdsSystemOptions = IfdsSystemOptions(), bannedPackagePrefixes: List = defaultBannedPackagePrefixes, - chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy = ClassChunkStrategy, + chunkStrategy: ChunkStrategy = ClassChunkStrategy, ): JcAsyncIfdsFacade { - val facade = unusedIfdsFacade(name, cp, graph, bannedPackagePrefixes, chunkStrategy) + val facade = unusedIfdsFacade(name, cp, graph, ifdsSystemOptions, bannedPackagePrefixes, chunkStrategy) return JcAsyncIfdsFacade(facade) } diff --git a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java index 677ca4324..a6aef8e6f 100644 --- a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java +++ b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java @@ -67,6 +67,7 @@ public void testJavaAnalysisApi() throws ExecutionException, InterruptedExceptio "ifds", applicationGraph.getClasspath(), applicationGraph, + new IfdsSystemOptions(), getDefaultBannedPackagePrefixes(), ChunkStrategiesKt.getClassChunkStrategy()); ifds.runAnalysis( diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt index fb1ef6505..67aa3515a 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt @@ -106,7 +106,7 @@ class IfdsSqlTest : BaseAnalysisTest() { val clazz = cp.findClass(className) val badMethod = clazz.methods.single { it.name == "bad" } - val ifds = taintIfdsFacade("ifds", cp, graph, defaultBannedPackagePrefixes) + val ifds = taintIfdsFacade("ifds", cp, graph) ifds.startAnalysis(badMethod) ifds.awaitAnalysis() diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt index 387616437..3d0c2fa2b 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt @@ -58,7 +58,7 @@ class IfdsUnusedTest : BaseAnalysisTest() { } private fun findSinks(method: JcMethod): Collection = runBlocking { - val system = unusedIfdsFacade("ifds", cp, graph, defaultBannedPackagePrefixes) + val system = unusedIfdsFacade("ifds", cp, graph) system.startAnalysis(method) system.awaitAnalysis() diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt index 2da62bc0e..544fca86c 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt @@ -60,7 +60,7 @@ class JodaDateTimeAnalysisTest : BaseTest() { @Test fun `test taint analysis`() = runBlocking { - val ifds = taintIfdsFacade("ifds", cp, graph, defaultBannedPackagePrefixes) + val ifds = taintIfdsFacade("ifds", cp, graph) val clazz = cp.findClass() val methods = clazz.declaredMethods ifds.runAnalysis(methods, timeout = 20.seconds) @@ -70,7 +70,7 @@ class JodaDateTimeAnalysisTest : BaseTest() { @Test fun `test NPE analysis`() = runBlocking { - val ifds = npeIfdsFacade("ifds", cp, graph, defaultBannedPackagePrefixes) + val ifds = npeIfdsFacade("ifds", cp, graph) val clazz = cp.findClass() val methods = clazz.declaredMethods ifds.runAnalysis(methods, timeout = 20.seconds) @@ -80,7 +80,7 @@ class JodaDateTimeAnalysisTest : BaseTest() { @Test fun `test unused variables analysis`() = runBlocking { - val ifds = unusedIfdsFacade("ifds", cp, graph, defaultBannedPackagePrefixes) + val ifds = unusedIfdsFacade("ifds", cp, graph) val clazz = cp.findClass() val methods = clazz.declaredMethods ifds.runAnalysis(methods, timeout = 20.seconds) From a56f4a208fb843e98384baf382592dc4b2797557 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Fri, 17 May 2024 16:20:55 +0300 Subject: [PATCH 58/64] Cleanup --- .../org/jacodb/actors/api/ActorFactory.kt | 2 +- .../jacodb/actors/api/options/SpawnOptions.kt | 2 -- .../org/jacodb/actors/api/signal/Signal.kt | 3 --- .../jacodb/actors/impl/ActorSystemOptions.kt | 2 +- .../analysis/custom/FlowAnalysisImpl.kt | 9 ++++---- .../analysis/custom/ForwardFlowAnalysis.kt | 3 +-- .../analysis/custom/NullAssumptionAnalysis.kt | 4 +--- .../custom/ReachingDefinitionsAnalysis.kt | 3 ++- .../analysis/ifds/actors/ChunkManager.kt | 2 +- .../org/jacodb/analysis/ifds/actors/Runner.kt | 4 +--- .../analysis/ifds/actors/RunnerStorage.kt | 1 - .../jacodb/analysis/ifds/domain/CallAction.kt | 6 ++--- .../analysis/ifds/domain/FlowFunctions.kt | 2 +- .../analysis/ifds/common/JcBaseAnalyzer.kt | 4 ++-- .../ifds/common/JcIndirectionHandler.kt | 1 - .../jacodb/analysis/ifds/npe/NpeAnalyzers.kt | 2 -- .../analysis/ifds/npe/NpeFlowFunctions.kt | 4 ++-- .../analysis/ifds/taint/TaintAnalyzers.kt | 1 - .../analysis/ifds/taint/TaintFlowFunctions.kt | 5 ++--- .../analysis/ifds/JavaAnalysisApiTest.java | 22 +++++++++---------- .../org/jacodb/analysis/ifds/IfdsSqlTest.kt | 1 - .../jacodb/analysis/ifds/IfdsUnusedTest.kt | 1 - .../analysis/ifds/JodaDateTimeAnalysisTest.kt | 1 - .../src/test/resources/config_small.json | 1 - 24 files changed, 33 insertions(+), 53 deletions(-) diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt index 35f1927f9..1cda3fb6b 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/ActorFactory.kt @@ -18,4 +18,4 @@ package org.jacodb.actors.api fun interface ActorFactory { fun ActorContext.create(): Actor -} \ No newline at end of file +} diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt index a1c55b2b5..6be2414b6 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/options/SpawnOptions.kt @@ -17,8 +17,6 @@ package org.jacodb.actors.api.options import kotlinx.coroutines.channels.Channel -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext class SpawnOptions( val channelFactory: ChannelFactory, diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt index ce2eeddc7..7a378a894 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/api/signal/Signal.kt @@ -16,11 +16,8 @@ package org.jacodb.actors.api.signal -import org.jacodb.actors.api.ActorRef - sealed interface Signal { data object Start : Signal data object PostStop : Signal data class Exception(val exception: java.lang.Exception) : Signal - class Terminated(val ref: ActorRef<*>) } diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemOptions.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemOptions.kt index f53bcd189..ca8406744 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemOptions.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemOptions.kt @@ -20,4 +20,4 @@ import kotlin.time.Duration data class ActorSystemOptions( val printStatisticsPeriod: Duration? = null, -) \ No newline at end of file +) diff --git a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/FlowAnalysisImpl.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/FlowAnalysisImpl.kt index eee2782a9..0f724923a 100644 --- a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/FlowAnalysisImpl.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/FlowAnalysisImpl.kt @@ -35,7 +35,6 @@ enum class Flow { abstract fun getFlow(e: FlowEntry): F? } - /** * Creates a new `Entry` graph based on a `JcGraph`. This includes pseudo topological order, local * access for predecessors and successors, a graph entry-point, connected component marker. @@ -43,7 +42,7 @@ enum class Flow { private fun JcBytecodeGraph.newScope( direction: FlowAnalysisDirection, entryFlow: T, - isForward: Boolean + isForward: Boolean, ): List> { val size = toList().size val s = ArrayDeque>(size) @@ -142,7 +141,7 @@ private fun JcBytecodeGraph.newScope( private fun FlowEntry.visitEntry( instructions: List, - visited: MutableMap> + visited: MutableMap>, ): Array> { val n = instructions.size return Array(n) { @@ -154,7 +153,7 @@ private fun FlowEntry.visitEntry( private fun NODE.toEntry( pred: FlowEntry?, - visited: MutableMap> + visited: MutableMap>, ): FlowEntry { // either we reach a new node or a merge node, the latter one is rare // so put and restore should be better that a lookup @@ -350,7 +349,7 @@ abstract class FlowAnalysisImpl(graph: JcBytecodeGraph) : Abstrac open fun runAnalysis( direction: FlowAnalysisDirection, inFlow: Map, - outFlow: Map + outFlow: Map, ): Int { val scope = graph.newScope(direction, newEntryFlow(), isForward).also { it.initFlow() diff --git a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/ForwardFlowAnalysis.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/ForwardFlowAnalysis.kt index 0636051a4..2fc9c7ad5 100644 --- a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/ForwardFlowAnalysis.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/ForwardFlowAnalysis.kt @@ -18,7 +18,6 @@ package org.jacodb.analysis.custom import org.jacodb.api.cfg.JcBytecodeGraph - abstract class ForwardFlowAnalysis(graph: JcBytecodeGraph) : FlowAnalysisImpl(graph) { override val isForward = true @@ -26,4 +25,4 @@ abstract class ForwardFlowAnalysis(graph: JcBytecodeGraph) : Flow override fun run() { runAnalysis(FlowAnalysisDirection.FORWARD, ins, outs) } -} \ No newline at end of file +} diff --git a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/NullAssumptionAnalysis.kt b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/NullAssumptionAnalysis.kt index 89ceb274b..85553588f 100644 --- a/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/NullAssumptionAnalysis.kt +++ b/jacodb-analysis/common/src/main/kotlin/org/jacodb/analysis/custom/NullAssumptionAnalysis.kt @@ -32,7 +32,6 @@ import org.jacodb.api.ext.cfg.arrayRef import org.jacodb.api.ext.cfg.callExpr import org.jacodb.api.ext.cfg.fieldRef - class NullAnalysisMap : HashMap { constructor() : super() @@ -59,7 +58,7 @@ open class NullAssumptionAnalysis(graph: JcGraph) : BackwardFlowAnalysis( ) : Actor { private val routerFactory = messageKeyRouter( - ifdsContext::runnerIdByMessage + keyExtractor = ifdsContext::runnerIdByMessage ) { runnerId -> Runner(this@ActorContext.self, ifdsContext, chunk, runnerId) } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt index 7f1462702..3d56acb8c 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/Runner.kt @@ -48,9 +48,7 @@ class Runner( RunnerStorage(this@ActorContext.self, runnerId) } - private val indirectionHandler = spawn( - "indirection", - ) { + private val indirectionHandler = spawn("indirection") { val indirectionHandler = ifdsContext.getIndirectionHandler(runnerId) IndirectionHandlerActor(this@ActorContext.self, indirectionHandler) } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt index 2c2679135..f84286aa2 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt @@ -104,7 +104,6 @@ class RunnerStorage( edge, subscribingEdge ) - } sendNotificationsOnExistingSubscribers( endSubscribers[edge.to].orEmpty() diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt index e3a9c7aa4..203fffc0c 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/CallAction.kt @@ -29,7 +29,7 @@ sealed interface CallAction { * ``` */ data class Return( - val fact: Fact + val fact: Fact, ) : CallAction /** @@ -49,6 +49,6 @@ sealed interface CallAction { * ``` */ data class Start( - val fact: Fact + val fact: Fact, ) : CallAction -} \ No newline at end of file +} diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt index 29451ab02..0ff234ab7 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/domain/FlowFunctions.kt @@ -47,7 +47,7 @@ interface FlowFunctions { fun call( callStatement: Stmt, returnSite: Stmt, - fact: Fact + fact: Fact, ): Collection> /** diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt index c79e52bac..0671e39d1 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcBaseAnalyzer.kt @@ -100,6 +100,7 @@ abstract class JcBaseAnalyzer( val newEdge = Edge(edge.from, Vertex(successor, action.fact)) processNewEdge(selfRunnerId, newEdge, reason) } + is CallAction.Start -> { val newEdge = Edge(edge.from, Vertex(edge.to.statement, action.fact)) val callMessage = UnresolvedCall(selfRunnerId, newEdge) @@ -124,7 +125,6 @@ abstract class JcBaseAnalyzer( } } - private fun MutableList.processResolvedCall( edge: Edge, method: JcMethod, @@ -171,7 +171,7 @@ abstract class JcBaseAnalyzer( private fun MutableList.processNotificationOnStart( callerEdge: Edge, - edge: Edge + edge: Edge, ) { val reason = Reason.ExitToReturnSite(callerEdge, edge) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt index 7e7c33b7c..6e5e41e15 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt @@ -59,7 +59,6 @@ class JcIndirectionHandler( val instanceClass = (callExpr.instance.type as? JcClassType)?.jcClass ?: return listOf(ResolvedCall(runnerId, edge, callee)) - val overrides = cache .computeIfAbsent(callee) { hierarchy.findOverrides(callee).toList() } .asSequence() diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt index 1627e0f57..1eebb205e 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeAnalyzers.kt @@ -35,7 +35,6 @@ import org.jacodb.taint.configuration.TaintMethodSink private val logger = mu.KotlinLogging.logger {} - class NpeAnalyzer( selfRunnerId: RunnerId, graph: JcApplicationGraph, @@ -51,7 +50,6 @@ class NpeAnalyzer( ?.let { it as TaintConfigurationFeature } } - override val flowFunctions: ForwardNpeFlowFunctions by lazy { ForwardNpeFlowFunctions(cp, taintConfigurationFeature) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt index 1a5fc83c8..d8d41ec12 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/NpeFlowFunctions.kt @@ -16,8 +16,6 @@ package org.jacodb.analysis.ifds.npe -import org.jacodb.analysis.ifds.domain.CallAction -import org.jacodb.analysis.ifds.domain.FlowFunctions import org.jacodb.analysis.ifds.config.BasicConditionEvaluator import org.jacodb.analysis.ifds.config.CallPositionToAccessPathResolver import org.jacodb.analysis.ifds.config.CallPositionToJcValueResolver @@ -25,6 +23,8 @@ import org.jacodb.analysis.ifds.config.EntryPointPositionToAccessPathResolver import org.jacodb.analysis.ifds.config.EntryPointPositionToJcValueResolver import org.jacodb.analysis.ifds.config.FactAwareConditionEvaluator import org.jacodb.analysis.ifds.config.TaintActionEvaluator +import org.jacodb.analysis.ifds.domain.CallAction +import org.jacodb.analysis.ifds.domain.FlowFunctions import org.jacodb.analysis.ifds.taint.TaintDomainFact import org.jacodb.analysis.ifds.taint.TaintZeroFact import org.jacodb.analysis.ifds.taint.Tainted diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt index f4d224916..5d9c931af 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintAnalyzers.kt @@ -32,7 +32,6 @@ import org.jacodb.taint.configuration.TaintMethodSink private val logger = mu.KotlinLogging.logger {} - class ForwardTaintAnalyzer( selfRunnerId: RunnerId, graph: JcApplicationGraph, diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt index 1708655ed..d5f043aec 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/TaintFlowFunctions.kt @@ -16,8 +16,6 @@ package org.jacodb.analysis.ifds.taint -import org.jacodb.analysis.ifds.domain.CallAction -import org.jacodb.analysis.ifds.domain.FlowFunctions import org.jacodb.analysis.ifds.config.BasicConditionEvaluator import org.jacodb.analysis.ifds.config.CallPositionToAccessPathResolver import org.jacodb.analysis.ifds.config.CallPositionToJcValueResolver @@ -25,6 +23,8 @@ import org.jacodb.analysis.ifds.config.EntryPointPositionToAccessPathResolver import org.jacodb.analysis.ifds.config.EntryPointPositionToJcValueResolver import org.jacodb.analysis.ifds.config.FactAwareConditionEvaluator import org.jacodb.analysis.ifds.config.TaintActionEvaluator +import org.jacodb.analysis.ifds.domain.CallAction +import org.jacodb.analysis.ifds.domain.FlowFunctions import org.jacodb.analysis.ifds.util.ElementAccessor import org.jacodb.analysis.ifds.util.getArgumentsOf import org.jacodb.analysis.ifds.util.onSome @@ -562,7 +562,6 @@ class BackwardTaintFlowFunctions( } } - // The "most default" behaviour is encapsulated here: return transmitTaintBackwardNormal(fact, callStatement).map { CallAction.Return(it) } } diff --git a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java index a6aef8e6f..7a07462ca 100644 --- a/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java +++ b/jacodb-analysis/taint/src/test/java/org/jacodb/analysis/ifds/JavaAnalysisApiTest.java @@ -60,20 +60,20 @@ public void testJavaAnalysisApi() throws ExecutionException, InterruptedExceptio List methodsToAnalyze = analyzedClass.getDeclaredMethods(); JcApplicationGraph applicationGraph = - newApplicationGraphForAnalysisAsync(classpath) - .get(); + newApplicationGraphForAnalysisAsync(classpath) + .get(); JcAsyncIfdsFacade ifds = asyncTaintIfdsFacade( - "ifds", - applicationGraph.getClasspath(), - applicationGraph, - new IfdsSystemOptions(), - getDefaultBannedPackagePrefixes(), - ChunkStrategiesKt.getClassChunkStrategy()); + "ifds", + applicationGraph.getClasspath(), + applicationGraph, + new IfdsSystemOptions(), + getDefaultBannedPackagePrefixes(), + ChunkStrategiesKt.getClassChunkStrategy()); ifds.runAnalysis( - methodsToAnalyze, - toDuration(30, DurationUnit.SECONDS)) - .get(); + methodsToAnalyze, + toDuration(30, DurationUnit.SECONDS)) + .get(); ifds.startAnalysis(methodsToAnalyze.get(0)).get(); diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt index 67aa3515a..0a0656295 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsSqlTest.kt @@ -19,7 +19,6 @@ package org.jacodb.analysis.ifds import kotlinx.coroutines.runBlocking import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import org.jacodb.analysis.ifds.common.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.result.buildTraceGraph import org.jacodb.analysis.ifds.sarif.sarifReportFromVulnerabilities import org.jacodb.analysis.ifds.sarif.toSarif diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt index 3d0c2fa2b..7e15e2720 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/IfdsUnusedTest.kt @@ -17,7 +17,6 @@ package org.jacodb.analysis.ifds import kotlinx.coroutines.runBlocking -import org.jacodb.analysis.ifds.common.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.unused.UnusedVulnerability import org.jacodb.analysis.ifds.unused.unusedIfdsFacade import org.jacodb.api.JcMethod diff --git a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt index 544fca86c..24035573d 100644 --- a/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt +++ b/jacodb-analysis/taint/src/test/kotlin/org/jacodb/analysis/ifds/JodaDateTimeAnalysisTest.kt @@ -18,7 +18,6 @@ package org.jacodb.analysis.ifds import kotlinx.coroutines.runBlocking import org.jacodb.analysis.graph.JcApplicationGraphImpl -import org.jacodb.analysis.ifds.common.defaultBannedPackagePrefixes import org.jacodb.analysis.ifds.npe.npeIfdsFacade import org.jacodb.analysis.ifds.taint.taintIfdsFacade import org.jacodb.analysis.ifds.unused.unusedIfdsFacade diff --git a/jacodb-analysis/taint/src/test/resources/config_small.json b/jacodb-analysis/taint/src/test/resources/config_small.json index b9d648e9d..cf227adc4 100644 --- a/jacodb-analysis/taint/src/test/resources/config_small.json +++ b/jacodb-analysis/taint/src/test/resources/config_small.json @@ -388,7 +388,6 @@ "_": "Result" } }, - { "_": "CopyAllMarks", "from": { From 194e21b7f276c71d9832371a8520b25d7c3200ad Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Fri, 17 May 2024 15:30:47 +0300 Subject: [PATCH 59/64] Reorder nested loops --- .../kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt index 6101208c2..d7bf5c5c8 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsFacade.kt @@ -70,8 +70,8 @@ open class JcIfdsFacade>( method: JcMethod, ) { val analyzer = context.getAnalyzer(startingRunnerId) - for (fact in analyzer.flowFunctions.obtainPossibleStartFacts(method)) { - for (entryPoint in graph.entryPoints(method)) { + for (entryPoint in graph.entryPoints(method)) { + for (fact in analyzer.flowFunctions.obtainPossibleStartFacts(method)) { val vertex = Vertex(entryPoint, fact) val edge = Edge(vertex, vertex) val newEdgeMessage = NewEdge(startingRunnerId, edge, Reason.Initial) From 526abc4de4b159b1dbe09b71644ea622ad758222 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Fri, 17 May 2024 15:33:26 +0300 Subject: [PATCH 60/64] Improve logging messages --- .../org/jacodb/actors/impl/actors/internal/WatcherActor.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/internal/WatcherActor.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/internal/WatcherActor.kt index a2268d53f..25ef5409a 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/internal/WatcherActor.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/actors/internal/WatcherActor.kt @@ -94,10 +94,10 @@ internal class WatcherActor( } private fun printStatistics() { - logger.info { "Actors: ${state.terminatedActors}/${watchList.size}" } + logger.info { "Actors (term/total)): ${state.terminatedActors}/${watchList.size}" } val percent = 100.0 * state.totalReceived / state.totalSent val left = state.totalSent - state.totalReceived - logger.info { "Messages: ${state.totalReceived}/${state.totalSent}\t${"%.2f".format(percent)}%\tLeft: $left" } + logger.info { "Messages (recv/sent): ${state.totalReceived}/${state.totalSent}\t${"%.2f".format(percent)}%\tLeft: $left" } } private fun checkTermination(computationFinished: CompletableDeferred) { From 320641dd59c170c582d6fce0f52aaf29adfaad30 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Fri, 17 May 2024 16:20:44 +0300 Subject: [PATCH 61/64] Use hashMapOf --- .../kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt index f84286aa2..dab2ff170 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/actors/RunnerStorage.kt @@ -49,9 +49,9 @@ class RunnerStorage( ) private val startSubscribers = - HashMap, HashSet>>() + hashMapOf, HashSet>>() private val endSubscribers = - HashMap, HashSet>>() + hashMapOf, HashSet>>() private val edges = hashSetOf>() private val reasons = hashMapOf, HashSet>>() From ab75c445261102d49fccdbb7c2e28751a0546bb2 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Fri, 17 May 2024 18:03:02 +0300 Subject: [PATCH 62/64] Fix typo in user actor name --- .../src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt index 781aee301..33fb932e8 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/ActorSystemImpl.kt @@ -78,7 +78,7 @@ internal class ActorSystemImpl( } companion object { - private const val USER_ACTOR_NAME = "usr" + private const val USER_ACTOR_NAME = "user" private const val WATCHER_ACTOR_NAME = "watcher" } From 05a1e00c980b193e0c8e45f3ee4d0adbc2bb0695 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Fri, 17 May 2024 18:23:21 +0300 Subject: [PATCH 63/64] Import --- .../jacodb/analysis/ifds/common/ChunkStrategies.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/ChunkStrategies.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/ChunkStrategies.kt index d4f656d27..355926d72 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/ChunkStrategies.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/ChunkStrategies.kt @@ -16,6 +16,7 @@ package org.jacodb.analysis.ifds.common +import org.jacodb.analysis.ifds.ChunkStrategy import org.jacodb.analysis.ifds.domain.Chunk import org.jacodb.api.JcClassOrInterface import org.jacodb.api.JcMethod @@ -24,7 +25,7 @@ import org.jacodb.api.ext.packageName data object SingletonChunk : Chunk -val SingletonChunkStrategy = org.jacodb.analysis.ifds.ChunkStrategy { +val SingletonChunkStrategy = ChunkStrategy { SingletonChunk } @@ -32,7 +33,7 @@ data class MethodChunk( val method: JcMethod, ) : Chunk -val MethodChunkStrategy = org.jacodb.analysis.ifds.ChunkStrategy { stmt -> +val MethodChunkStrategy = ChunkStrategy { stmt -> MethodChunk(stmt.location.method) } @@ -40,12 +41,12 @@ data class ClassChunk( val jcClass: JcClassOrInterface, ) : Chunk -val ClassChunkStrategy = org.jacodb.analysis.ifds.ChunkStrategy { stmt -> +val ClassChunkStrategy = ChunkStrategy { stmt -> val jcClass = stmt.location.method.enclosingClass ClassChunk(jcClass) } -val ClassWithNestedChunkStrategy = org.jacodb.analysis.ifds.ChunkStrategy { stmt -> +val ClassWithNestedChunkStrategy = ChunkStrategy { stmt -> val jClass = generateSequence(stmt.location.method.enclosingClass) { it.outerClass } .last() ClassChunk(jClass) @@ -55,6 +56,6 @@ data class PackageChunk( val packageName: String, ) : Chunk -val PackageChunkStrategy = org.jacodb.analysis.ifds.ChunkStrategy { stmt -> +val PackageChunkStrategy = ChunkStrategy { stmt -> PackageChunk(stmt.location.method.enclosingClass.packageName) } From 1b5872c24e28192059c4ba63e1944d9478988266 Mon Sep 17 00:00:00 2001 From: Konstantin Chukharev Date: Fri, 17 May 2024 20:24:40 +0300 Subject: [PATCH 64/64] Support "unknown chunks" (null) --- .../jacodb/actors/impl/routing/Builders.kt | 4 +-- .../actors/impl/routing/MessageKeyRouter.kt | 6 ++--- .../org/jacodb/analysis/ifds/ChunkResolver.kt | 7 +----- .../org/jacodb/analysis/ifds/ChunkStrategy.kt | 23 +++++++++++++++++ .../org/jacodb/analysis/ifds/IfdsContext.kt | 2 +- .../analysis/ifds/common/JcChunkResolver.kt | 4 +-- .../analysis/ifds/common/JcIfdsContext.kt | 10 +++++--- .../ifds/common/JcIndirectionHandler.kt | 25 +++++++++++++++++++ .../org/jacodb/analysis/ifds/npe/Builders.kt | 1 + .../jacodb/analysis/ifds/taint/Builders.kt | 1 + .../jacodb/analysis/ifds/unused/Builders.kt | 1 + 11 files changed, 66 insertions(+), 18 deletions(-) create mode 100644 jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkStrategy.kt diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt index 410a8950c..59699d3a7 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/Builders.kt @@ -37,8 +37,8 @@ fun randomRouter( RandomRouter(size, random, routeeSpawnOptions, routeeFactory) } -fun messageKeyRouter( - keyExtractor: (Message) -> Key, +fun messageKeyRouter( + keyExtractor: (Message) -> Key?, routeeNameFactory: (Key) -> String = { it.toString() }, routeeSpawnOptions: SpawnOptions = SpawnOptions.default, routeeFactory: KeyRouteeFactory, diff --git a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt index 02416aea9..c0ad32e4a 100644 --- a/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt +++ b/jacodb-analysis/actors/src/main/kotlin/org/jacodb/actors/impl/routing/MessageKeyRouter.kt @@ -24,8 +24,8 @@ import org.jacodb.actors.api.options.SpawnOptions internal typealias KeyRouteeFactory = ActorContext.(Key) -> Actor context(ActorContext) -internal class MessageKeyRouter( - private val keyExtractor: (Message) -> Key, +internal class MessageKeyRouter( + private val keyExtractor: (Message) -> Key?, private val routeeNameFactory: (Key) -> String, private val routeeSpawnOptions: SpawnOptions, private val routeeFactory: KeyRouteeFactory, @@ -33,7 +33,7 @@ internal class MessageKeyRouter( private val routees = hashMapOf>() override suspend fun receive(message: Message) { - val key = keyExtractor(message) + val key = keyExtractor(message) ?: return val routee = routees.computeIfAbsent(key) { val name = routeeNameFactory(key) spawn(name, routeeSpawnOptions) { routeeFactory(key) } diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkResolver.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkResolver.kt index a90a58344..ee2fb6d1c 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkResolver.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkResolver.kt @@ -20,10 +20,5 @@ import org.jacodb.analysis.ifds.domain.Chunk import org.jacodb.analysis.ifds.messages.RunnerMessage fun interface ChunkResolver { - fun chunkByMessage(message: RunnerMessage): Chunk + fun chunkByMessage(message: RunnerMessage): Chunk? } - -fun interface ChunkStrategy { - fun chunkByStmt(stmt: Stmt): Chunk -} - diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkStrategy.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkStrategy.kt new file mode 100644 index 000000000..a5c3786d6 --- /dev/null +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/ChunkStrategy.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2022 UnitTestBot contributors (utbot.org) + *

+ * 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 + *

+ * 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. + */ + +package org.jacodb.analysis.ifds + +import org.jacodb.analysis.ifds.domain.Chunk + +fun interface ChunkStrategy { + fun chunkByStmt(stmt: Stmt): Chunk? +} diff --git a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt index 87d6251f2..8c070a3d2 100644 --- a/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt +++ b/jacodb-analysis/ifds/src/main/kotlin/org/jacodb/analysis/ifds/IfdsContext.kt @@ -25,7 +25,7 @@ import org.jacodb.analysis.ifds.messages.RunnerMessage interface IfdsContext { val options: IfdsSystemOptions - fun chunkByMessage(message: RunnerMessage): Chunk + fun chunkByMessage(message: RunnerMessage): Chunk? fun runnerIdByMessage(message: RunnerMessage): RunnerId fun getAnalyzer(runnerId: RunnerId): Analyzer diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt index 72325add9..2f061065b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcChunkResolver.kt @@ -40,7 +40,7 @@ class JcChunkResolver( private val chunkStrategy: org.jacodb.analysis.ifds.ChunkStrategy, ) : ChunkResolver { @Suppress("UNCHECKED_CAST") - override fun chunkByMessage(message: RunnerMessage): Chunk = + override fun chunkByMessage(message: RunnerMessage): Chunk? = when (message) { is AnalyzerMessage<*, *> -> { when (message) { @@ -122,4 +122,4 @@ class JcChunkResolver( } } } -} \ No newline at end of file +} diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt index 30b7ca81c..703b23e23 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIfdsContext.kt @@ -17,6 +17,7 @@ package org.jacodb.analysis.ifds.common import org.jacodb.analysis.ifds.ChunkResolver +import org.jacodb.analysis.ifds.ChunkStrategy import org.jacodb.analysis.ifds.IfdsContext import org.jacodb.analysis.ifds.IfdsSystemOptions import org.jacodb.analysis.ifds.domain.Chunk @@ -32,11 +33,12 @@ class JcIfdsContext( private val cp: JcClasspath, override val options: IfdsSystemOptions, private val bannedPackagePrefixes: List, - private val chunkStrategy: ChunkResolver, + val strategy: ChunkStrategy, + private val resolver: ChunkResolver, private val analyzerFactory: (RunnerId) -> JcBaseAnalyzer, ) : IfdsContext { - override fun chunkByMessage(message: RunnerMessage): Chunk = - chunkStrategy.chunkByMessage(message) + override fun chunkByMessage(message: RunnerMessage): Chunk? = + resolver.chunkByMessage(message) override fun runnerIdByMessage(message: RunnerMessage): RunnerId = message.runnerId @@ -47,5 +49,5 @@ class JcIfdsContext( analyzers.computeIfAbsent(runnerId, analyzerFactory) override fun getIndirectionHandler(runnerId: RunnerId): IndirectionHandler = - JcIndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, runnerId) + JcIndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, runnerId, this) } diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt index 6e5e41e15..9f2c9cd02 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/common/JcIndirectionHandler.kt @@ -36,10 +36,35 @@ class JcIndirectionHandler( private val hierarchy: HierarchyExtension, private val bannedPackagePrefixes: List, private val runnerId: RunnerId, + private val context: JcIfdsContext<*>, ) : IndirectionHandler { private val cache = hashMapOf>() override fun handle(message: IndirectionMessage): Collection { + val result = handleEx(message) + if (result.size == 1 && result.single() is NoResolvedCall<*, *>) { + return result + } + + if (result.isEmpty()) return result + + val calls = result.filterIsInstance>() + val allowedCalls = calls.filter { + val method = it.method as JcMethod + val stmt = method.instList.firstOrNull() ?: return@filter false + + context.strategy.chunkByStmt(stmt) != null + } + + if (allowedCalls.isEmpty()) { + val proto = calls.first() + return listOf(NoResolvedCall(proto.runnerId, proto.edge)) + } + + return allowedCalls + } + + private fun handleEx(message: IndirectionMessage): Collection { @Suppress("UNCHECKED_CAST") message as? UnresolvedCall ?: error("Unexpected message: $message") diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt index 9335dd79e..723c5e4a0 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/npe/Builders.kt @@ -41,6 +41,7 @@ fun npeIfdsContext( cp, ifdsSystemOptions, bannedPackagePrefixes, + chunkStrategy, JcChunkResolver(chunkStrategy) ) { runnerId -> val analyzer = when (runnerId) { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt index 49d12842a..6e004ce9b 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/taint/Builders.kt @@ -41,6 +41,7 @@ fun taintIfdsContext( cp, ifdsSystemOptions, bannedPackagePrefixes, + chunkStrategy, JcChunkResolver(chunkStrategy) ) { runnerId -> when (runnerId) { diff --git a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt index 77dc57f3e..d91130429 100644 --- a/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt +++ b/jacodb-analysis/taint/src/main/kotlin/org/jacodb/analysis/ifds/unused/Builders.kt @@ -41,6 +41,7 @@ fun unusedIfdsContext( cp, ifdsSystemOptions, bannedPackagePrefixes, + chunkStrategy, JcChunkResolver(chunkStrategy) ) { runnerId -> when (runnerId) {