diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/MethodAnalyzer.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/MethodAnalyzer.kt index 9dcfabcbc..253feaab4 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/MethodAnalyzer.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/MethodAnalyzer.kt @@ -69,7 +69,7 @@ interface MethodAnalyzer { fun handleMethodSideEffectRequirement( currentEdge: FactToFact, - methodInitialFactBase: AccessPathBase, + callee: MethodEntryPoint, methodSideEffectRequirements: List ) @@ -80,11 +80,13 @@ interface MethodAnalyzer { fun handleZeroToFactMethodSideEffectSummary( summarySubs: List, + callee: MethodEntryPoint, sideEffectSummaries: List ) fun handleFactToFactMethodSideEffectSummary( summarySubs: List, + callee: MethodEntryPoint, sideEffectSummaries: List ) @@ -98,24 +100,19 @@ interface MethodAnalyzer { fun collectStats(stats: MethodStats) data class ZeroToFactSub( - val currentEdge: ZeroToFact, - val methodInitialFactBase: AccessPathBase + val currentEdge: ZeroToFact ) data class FactToFactSub( - val currentEdge: FactToFact, - val methodInitialFactBase: AccessPathBase + val currentEdge: FactToFact ) data class NDFactToFactSub( - val currentEdge: NDFactToFact, - val methodInitialFactBase: AccessPathBase + val currentEdge: NDFactToFact ) fun handleResolvedMethodCall(method: MethodWithContext, handler: MethodCallHandler) - fun handleResolvedMethodCall(entryPoint: MethodEntryPoint, handler: MethodCallHandler) - fun handleMethodCallResolutionFailure( callExpr: CommonCallExpr, handler: MethodCallResolutionFailureHandler @@ -132,7 +129,8 @@ interface MethodAnalyzer { fun resolveCalleeFact( statement: CommonInst, - factAp: FinalFactAp + factAp: FinalFactAp, + callee: MethodEntryPoint, ): Set fun allIntraProceduralFacts(): Map> @@ -142,10 +140,12 @@ interface MethodAnalyzer { fun resetApManager(apManager: ApManager) sealed interface MethodCallHandler { - data class ZeroToZeroHandler(val currentEdge: ZeroToZero) : MethodCallHandler - data class ZeroToFactHandler(val currentEdge: ZeroToFact, val startFactBase: AccessPathBase) : MethodCallHandler - data class FactToFactHandler(val currentEdge: FactToFact, val startFactBase: AccessPathBase) : MethodCallHandler - data class NDFactToFactHandler(val currentEdge: NDFactToFact, val startFactBase: AccessPathBase) : MethodCallHandler + val currentEdge: Edge + + data class ZeroToZeroHandler(override val currentEdge: ZeroToZero) : MethodCallHandler + data class ZeroToFactHandler(override val currentEdge: ZeroToFact, val startFactBase: AccessPathBase) : MethodCallHandler + data class FactToFactHandler(override val currentEdge: FactToFact, val startFactBase: AccessPathBase) : MethodCallHandler + data class NDFactToFactHandler(override val currentEdge: NDFactToFact, val startFactBase: AccessPathBase) : MethodCallHandler } sealed interface MethodCallResolutionFailureHandler { @@ -405,18 +405,6 @@ class NormalMethodAnalyzer( handleUnchangedStatementEdge(edge) } - is MethodCallFlowFunction.Drop -> { - // do nothing - } - - is MethodCallFlowFunction.CallToReturnZeroFact -> { - handleStatementEdge(edge, ZeroToZero(methodEntryPoint, edge.statement)) - } - - is MethodCallFlowFunction.CallToReturnZFact -> { - handleStatementEdge(edge, ZeroToFact(methodEntryPoint, edge.statement, fact.factAp)) - } - is MethodCallFlowFunction.CallToStartZeroFact -> { val callerEdge = ZeroToZero(methodEntryPoint, edge.statement) @@ -432,21 +420,11 @@ class NormalMethodAnalyzer( resolveMethodCall(callExpr, edge.statement, handler, failureHandler) } - is MethodCallFlowFunction.CallToReturnFFact -> { - val edgeAfterStatement = FactToFact(methodEntryPoint, fact.initialFactAp, edge.statement, fact.factAp) - handleStatementEdge(edge, edgeAfterStatement) - } - - is MethodCallFlowFunction.CallToReturnNonDistributiveFact -> { - val edgeAfterStatement = NDFactToFact( - methodEntryPoint, fact.initialFacts, edge.statement, fact.factAp - ) - handleStatementEdge(edge, edgeAfterStatement) - } - is MethodCallFlowFunction.ZeroSideEffect -> { addZeroSideEffect(fact.kind) } + + is MethodCallFlowFunction.Call2ReturnFact -> propagateCall2ReturnFact(edge, fact) } } @@ -460,20 +438,6 @@ class NormalMethodAnalyzer( handleUnchangedStatementEdge(edge) } - is MethodCallFlowFunction.Drop -> { - // do nothing - } - - is MethodCallFlowFunction.CallToReturnFFact -> { - val edgeAfterStatement = FactToFact(methodEntryPoint, fact.initialFactAp, edge.statement, fact.factAp) - handleStatementEdge(edge, edgeAfterStatement) - } - - is MethodCallFlowFunction.CallToReturnZFact -> { - val edgeAfterStatement = ZeroToFact(methodEntryPoint, edge.statement, fact.factAp) - handleStatementEdge(edge, edgeAfterStatement) - } - is MethodCallFlowFunction.CallToStartFFact -> { val callerEdge = FactToFact(methodEntryPoint, fact.initialFactAp, edge.statement, fact.callerFactAp) @@ -492,12 +456,7 @@ class NormalMethodAnalyzer( addFactSideEffect(edge, fact.initialFactAp, fact.kind) } - is MethodCallFlowFunction.CallToReturnNonDistributiveFact -> { - val edgeAfterStatement = NDFactToFact( - methodEntryPoint, fact.initialFacts, edge.statement, fact.factAp - ) - handleStatementEdge(edge, edgeAfterStatement) - } + is MethodCallFlowFunction.Call2ReturnFact -> propagateCall2ReturnFact(edge, fact) } } @@ -511,15 +470,81 @@ class NormalMethodAnalyzer( handleUnchangedStatementEdge(edge) } - is MethodCallFlowFunction.Drop -> { - // do nothing + is MethodCallFlowFunction.CallToStartNDFFact -> { + val callerEdge = NDFactToFact(methodEntryPoint, fact.initialFacts, edge.statement, fact.callerFactAp) + + val handler = MethodCallHandler.NDFactToFactHandler(callerEdge, fact.startFactBase) + val failureHandler = MethodCallResolutionFailureHandler.NDFactToFactHandler(callerEdge, fact.startFactBase) + resolveMethodCall(callExpr, edge.statement, handler, failureHandler) } - is MethodCallFlowFunction.CallToReturnNonDistributiveFact -> { - val edgeAfterStatement = NDFactToFact( - methodEntryPoint, fact.initialFacts, edge.statement, fact.factAp - ) - handleStatementEdge(edge, edgeAfterStatement) + is MethodCallFlowFunction.Call2ReturnFact -> propagateCall2ReturnFact(edge, fact) + } + } + + private fun propagateZeroCallSuccessFact( + edge: ZeroInitialEdge, + fact: MethodCallFlowFunction.ZeroCallSuccessFact, + method: MethodWithContext, + ) { + when (fact) { + is MethodCallFlowFunction.CallToStartZeroFact -> { + val callerEdge = ZeroToZero(methodEntryPoint, edge.statement) + handleMethodCall(method) { runner.subscribeOnMethodSummaries(callerEdge, it) } + } + + is MethodCallFlowFunction.CallToStartZFact -> { + val callerEdge = ZeroToFact(methodEntryPoint, edge.statement, fact.callerFactAp) + handleMethodCall(method) { runner.subscribeOnMethodSummaries(callerEdge, it, fact.startFactBase) } + } + + is MethodCallFlowFunction.Call2ReturnFact -> propagateCall2ReturnFact(edge, fact) + } + } + + private fun propagateFactCallSuccessFact( + edge: FactToFact, + fact: MethodCallFlowFunction.FactCallSuccessFact, + method: MethodWithContext, + ) { + when (fact) { + is MethodCallFlowFunction.CallToStartFFact -> { + val callerEdge = FactToFact(methodEntryPoint, fact.initialFactAp, edge.statement, fact.callerFactAp) + handleInputFactChange(edge.initialFactAp, callerEdge.initialFactAp) + handleMethodCall(method) { runner.subscribeOnMethodSummaries(callerEdge, it, fact.startFactBase) } + } + + is MethodCallFlowFunction.SideEffectRequirement -> { + addSideEffectRequirement(edge, fact.initialFactAp) + } + + is MethodCallFlowFunction.FactSideEffect -> { + addFactSideEffect(edge, fact.initialFactAp, fact.kind) + } + + is MethodCallFlowFunction.Call2ReturnFact -> propagateCall2ReturnFact(edge, fact) + } + } + + private fun propagateNDFactCallSuccessFact( + edge: NDFactToFact, + fact: MethodCallFlowFunction.NDFactCallSuccessFact, + method: MethodWithContext, + ) { + when (fact) { + is MethodCallFlowFunction.CallToStartNDFFact -> { + val callerEdge = NDFactToFact(methodEntryPoint, fact.initialFacts, edge.statement, fact.callerFactAp) + handleMethodCall(method) { runner.subscribeOnMethodSummaries(callerEdge, it, fact.startFactBase) } + } + + is MethodCallFlowFunction.Call2ReturnFact -> propagateCall2ReturnFact(edge, fact) + } + } + + private fun propagateCall2ReturnFact(edge: Edge, fact: MethodCallFlowFunction.Call2ReturnFact) { + when (fact) { + is MethodCallFlowFunction.CallToReturnZeroFact -> { + handleStatementEdge(edge, ZeroToZero(methodEntryPoint, edge.statement)) } is MethodCallFlowFunction.CallToReturnZFact -> { @@ -527,12 +552,20 @@ class NormalMethodAnalyzer( handleStatementEdge(edge, edgeAfterStatement) } - is MethodCallFlowFunction.CallToStartNDFFact -> { - val callerEdge = NDFactToFact(methodEntryPoint, fact.initialFacts, edge.statement, fact.callerFactAp) + is MethodCallFlowFunction.CallToReturnFFact -> { + val edgeAfterStatement = FactToFact(methodEntryPoint, fact.initialFactAp, edge.statement, fact.factAp) + handleStatementEdge(edge, edgeAfterStatement) + } - val handler = MethodCallHandler.NDFactToFactHandler(callerEdge, fact.startFactBase) - val failureHandler = MethodCallResolutionFailureHandler.NDFactToFactHandler(callerEdge, fact.startFactBase) - resolveMethodCall(callExpr, edge.statement, handler, failureHandler) + is MethodCallFlowFunction.CallToReturnNonDistributiveFact -> { + val edgeAfterStatement = NDFactToFact( + methodEntryPoint, fact.initialFacts, edge.statement, fact.factAp + ) + handleStatementEdge(edge, edgeAfterStatement) + } + + is MethodCallFlowFunction.Drop -> { + // do nothing } } } @@ -743,27 +776,51 @@ class NormalMethodAnalyzer( } override fun handleResolvedMethodCall(method: MethodWithContext, handler: MethodCallHandler) { - for (ep in methodEntryPoints(method)) { - handleMethodCall(handler, ep) - } - } + val statement = handler.currentEdge.statement + val callExpr = analysisManager.getCallExpr(statement) ?: error("Expected call expression") + val returnValue: CommonValue? = (statement as? CommonAssignInst)?.lhv + val flowFunction = analysisManager.getMethodCallFlowFunction( + apManager, + analysisContext, + returnValue, + callExpr, + statement, + generateTrace = false, + ) - override fun handleResolvedMethodCall(entryPoint: MethodEntryPoint, handler: MethodCallHandler) { - handleMethodCall(handler, entryPoint) - } + when (handler) { + is MethodCallHandler.ZeroToZeroHandler -> { + flowFunction.propagateZeroToZeroResolutionSuccess(method).forEach { + propagateZeroCallSuccessFact(handler.currentEdge, it, method) + } + } - private fun handleMethodCall(handler: MethodCallHandler, ep: MethodEntryPoint) = when (handler) { - is MethodCallHandler.ZeroToZeroHandler -> - runner.subscribeOnMethodSummaries(handler.currentEdge, ep) + is MethodCallHandler.ZeroToFactHandler -> { + flowFunction.propagateZeroToFactResolutionSuccess(handler.currentEdge.factAp, handler.startFactBase, method).forEach { + propagateZeroCallSuccessFact(handler.currentEdge, it, method) + } + } - is MethodCallHandler.ZeroToFactHandler -> - runner.subscribeOnMethodSummaries(handler.currentEdge, ep, handler.startFactBase) + is MethodCallHandler.FactToFactHandler -> { + val edge = handler.currentEdge + flowFunction.propagateFactToFactResolutionSuccess(edge.initialFactAp, edge.factAp, handler.startFactBase, method).forEach { + propagateFactCallSuccessFact(edge, it, method) + } + } - is MethodCallHandler.FactToFactHandler -> - runner.subscribeOnMethodSummaries(handler.currentEdge, ep, handler.startFactBase) + is MethodCallHandler.NDFactToFactHandler -> { + val edge = handler.currentEdge + flowFunction.propagateNDFactToFactResolutionSuccess(edge.initialFacts, edge.factAp, handler.startFactBase, method).forEach { + propagateNDFactCallSuccessFact(edge, it, method) + } + } + } + } - is MethodCallHandler.NDFactToFactHandler -> - runner.subscribeOnMethodSummaries(handler.currentEdge, ep, handler.startFactBase) + private inline fun handleMethodCall(method: MethodWithContext, subscribeOnMethodSummaries: (MethodEntryPoint) -> Unit) { + for (ep in methodEntryPoints(method)) { + subscribeOnMethodSummaries(ep) + } } override fun handleMethodCallResolutionFailure( @@ -826,14 +883,21 @@ class NormalMethodAnalyzer( override fun handleMethodSideEffectRequirement( currentEdge: FactToFact, - methodInitialFactBase: AccessPathBase, + callee: MethodEntryPoint, methodSideEffectRequirements: List ) { - val methodInitialFact = currentEdge.factAp.rebase(methodInitialFactBase) - val exclusionRefinements = methodSideEffectRequirements.mapNotNull { methodSinkRequirement -> - MethodSummaryEdgeApplicationUtils.emptyDeltaExclusionRefinementOrNull( - methodInitialFact, methodSinkRequirement - ) + val summaryHandler = analysisManager.getMethodCallSummaryHandler( + apManager, analysisContext, currentEdge.statement + ) + + val exclusionRefinements = mutableListOf() + methodSideEffectRequirements.forEach { methodSinkRequirement -> + val mappedRequirements = summaryHandler.prepareSummaryInitialFact(methodSinkRequirement, callee) + mappedRequirements.mapNotNullTo(exclusionRefinements) { mappedRequirement -> + MethodSummaryEdgeApplicationUtils.emptyDeltaExclusionRefinementOrNull( + currentEdge.factAp, mappedRequirement + ) + } } if (exclusionRefinements.isEmpty()) { @@ -865,6 +929,7 @@ class NormalMethodAnalyzer( override fun handleZeroToFactMethodSideEffectSummary( summarySubs: List, + callee: MethodEntryPoint, sideEffectSummaries: List ) { for (sub in summarySubs) { @@ -875,12 +940,20 @@ class NormalMethodAnalyzer( sub.currentEdge.statement, runner ) + val summaryHandler = analysisManager.getMethodCallSummaryHandler( + apManager, analysisContext, sub.currentEdge.statement + ) + + val summariesToApply = sideEffectSummaries.flatMap { se -> + summaryHandler.prepareSummaryInitialFact(se.initialFactAp, callee).map { mappedInitialFact -> + SideEffectSummary.FactSideEffectSummary(mappedInitialFact, se.kind) + } + } applyMethodSideEffectSummaries( currentEdge = sub.currentEdge, currentEdgeFactAp = sub.currentEdge.factAp, - methodInitialFactBase = sub.methodInitialFactBase, - sideEffectSummaries = sideEffectSummaries, + sideEffectSummaries = summariesToApply, handleSideEffect = handler::handleZeroToFact ) } @@ -888,6 +961,7 @@ class NormalMethodAnalyzer( override fun handleFactToFactMethodSideEffectSummary( summarySubs: List, + callee: MethodEntryPoint, sideEffectSummaries: List ) { for (sub in summarySubs) { @@ -898,12 +972,20 @@ class NormalMethodAnalyzer( sub.currentEdge.statement, runner, ) + val summaryHandler = analysisManager.getMethodCallSummaryHandler( + apManager, analysisContext, sub.currentEdge.statement + ) + + val summariesToApply = sideEffectSummaries.flatMap { se -> + summaryHandler.prepareSummaryInitialFact(se.initialFactAp, callee).map { mappedInitialFact -> + SideEffectSummary.FactSideEffectSummary(mappedInitialFact, se.kind) + } + } applyMethodSideEffectSummaries( currentEdge = sub.currentEdge, currentEdgeFactAp = sub.currentEdge.factAp, - methodInitialFactBase = sub.methodInitialFactBase, - sideEffectSummaries = sideEffectSummaries, + sideEffectSummaries = summariesToApply, ) { currentFactAp, summaryEffect, kind -> handler.handleFactToFact(sub.currentEdge.initialFactAp, currentFactAp, summaryEffect, kind) } @@ -961,11 +1043,19 @@ class NormalMethodAnalyzer( ) { summaryEdgesHandled++ - val applicableSummaries = methodSummaries.filter { isApplicableExitToReturnEdge(it) } val handler = analysisManager.getMethodCallSummaryHandler( apManager, analysisContext, currentEdge.statement ) + val applicableSummaries = methodSummaries.flatMap { summary -> + if (!isApplicableExitToReturnEdge(summary)) return@flatMap emptyList() + + when (summary) { + is ZeroToZero -> listOf(summary) + is ZeroToFact -> handler.prepareZeroToFactSummary(summary) + } + } + for (methodSummary in applicableSummaries) { if (!cancellation.isActive()) return @@ -997,7 +1087,6 @@ class NormalMethodAnalyzer( applyMethodSummaries( currentEdge = sub.currentEdge, currentEdgeFactAp = sub.currentEdge.factAp, - methodInitialFactBase = sub.methodInitialFactBase, methodSummaries = summariesToApply, handleSummaryEdge = handler::handleZeroToFact ) @@ -1010,7 +1099,7 @@ class NormalMethodAnalyzer( ) { handleMethodNDSummariesSub( summarySubs, methodSummaries, - { currentEdge }, { currentEdge.factAp }, { methodInitialFactBase } + { currentEdge }, { currentEdge.factAp } ) } @@ -1034,7 +1123,6 @@ class NormalMethodAnalyzer( applyMethodSummaries( currentEdge = sub.currentEdge, currentEdgeFactAp = sub.currentEdge.factAp, - methodInitialFactBase = sub.methodInitialFactBase, methodSummaries = summariesToApply, handleSummaryEdge = { currentFactAp: FinalFactAp, summaryEffect: SummaryEdgeApplication, summaryEdge: SummaryEdge -> handler.handleFactToFact(sub.currentEdge.initialFactAp, currentFactAp, summaryEffect, summaryEdge) @@ -1049,7 +1137,7 @@ class NormalMethodAnalyzer( ) { handleMethodNDSummariesSub( summarySubs, methodSummaries, - { currentEdge }, { currentEdge.factAp }, { methodInitialFactBase } + { currentEdge }, { currentEdge.factAp } ) } @@ -1073,7 +1161,6 @@ class NormalMethodAnalyzer( applyMethodSummaries( currentEdge = sub.currentEdge, currentEdgeFactAp = sub.currentEdge.factAp, - methodInitialFactBase = sub.methodInitialFactBase, methodSummaries = summariesToApply, handleSummaryEdge = { currentFactAp: FinalFactAp, summaryEffect: SummaryEdgeApplication, summaryEdge: SummaryEdge -> handler.handleNDFactToFact(sub.currentEdge.initialFacts, currentFactAp, summaryEffect, summaryEdge) @@ -1088,21 +1175,19 @@ class NormalMethodAnalyzer( ) { handleMethodNDSummariesSub( summarySubs, methodSummaries, - { currentEdge }, { currentEdge.factAp }, { methodInitialFactBase } + { currentEdge }, { currentEdge.factAp } ) } private fun applyMethodSummaries( currentEdge: Edge, currentEdgeFactAp: FinalFactAp, - methodInitialFactBase: AccessPathBase, methodSummaries: List, handleSummaryEdge: (currentFactAp: FinalFactAp, summaryEffect: SummaryEdgeApplication, summaryEdge: SummaryEdge) -> Set ) { applyMethodAnySummaries( currentEdge, currentEdgeFactAp, - methodInitialFactBase, methodSummaries, { it.initialFactAp } ) { currentFactAp, summaryEdgeEffect, methodSummary -> @@ -1113,14 +1198,12 @@ class NormalMethodAnalyzer( private fun applyMethodSideEffectSummaries( currentEdge: Edge, currentEdgeFactAp: FinalFactAp, - methodInitialFactBase: AccessPathBase, sideEffectSummaries: List, handleSideEffect: (currentFactAp: FinalFactAp, summaryEffect: SummaryEdgeApplication, kind: SideEffectKind) -> Set ) { applyMethodAnySummaries( currentEdge, currentEdgeFactAp, - methodInitialFactBase, sideEffectSummaries, { it.initialFactAp } ) { currentFactAp, summaryEdgeEffect, methodSummary -> @@ -1131,19 +1214,16 @@ class NormalMethodAnalyzer( private inline fun applyMethodAnySummaries( currentEdge: Edge, currentEdgeFactAp: FinalFactAp, - methodInitialFactBase: AccessPathBase, methodSummaries: List, getSummaryInitialFact: (S) -> InitialFactAp, handleSummary: (currentFactAp: FinalFactAp, summaryEffect: SummaryEdgeApplication, S) -> Set ) { - val methodInitialFact = currentEdgeFactAp.rebase(methodInitialFactBase) - val summaries = methodSummaries.groupByTo(hashMapOf()) { getSummaryInitialFact(it) } for ((summaryInitialFact, summaryEdges) in summaries) { if (!cancellation.isActive()) return val summaryEdgeEffects = MethodSummaryEdgeApplicationUtils.tryApplySummaryEdge( - methodInitialFact, summaryInitialFact + currentEdgeFactAp, summaryInitialFact ) for (summaryEdgeEffect in summaryEdgeEffects) { @@ -1162,7 +1242,6 @@ class NormalMethodAnalyzer( methodSummaries: List, subEdge: Sub.() -> Edge, subFact: Sub.() -> FinalFactAp, - subInitialFactBase: Sub.() -> AccessPathBase, ) { summaryEdgesHandled++ @@ -1183,7 +1262,6 @@ class NormalMethodAnalyzer( summaryHandler = handler, currentEdge = currentEdge, currentEdgeFactAp = sub.subFact(), - methodInitialFactBase = sub.subInitialFactBase(), methodSummaries = summariesToApply, ) } @@ -1193,22 +1271,19 @@ class NormalMethodAnalyzer( summaryHandler: MethodCallSummaryHandler, currentEdge: Edge, currentEdgeFactAp: FinalFactAp, - methodInitialFactBase: AccessPathBase, - methodSummaries: List, + methodSummaries: List, ) { - val methodInitialFact = currentEdgeFactAp.rebase(methodInitialFactBase) - nextSummary@for (summaryEdge in methodSummaries) { if (!cancellation.isActive()) return val requiredFacts = mutableListOf() - for (summaryInitialFact in summaryEdge.initialFacts) { - if (!methodInitialFact.matchNDInitial(summaryInitialFact)) { + for (summaryInitialFact in summaryEdge.initial) { + if (!currentEdgeFactAp.matchNDInitial(summaryInitialFact)) { requiredFacts.add(summaryInitialFact) } } - if (requiredFacts.size == summaryEdge.initialFacts.size) continue + if (requiredFacts.size == summaryEdge.initial.size) continue val requiredInitials = mutableListOf>>() for (requiredFact in requiredFacts) { @@ -1220,13 +1295,7 @@ class NormalMethodAnalyzer( factAtStatement.rebase(requiredFact.base).matchNDInitial(requiredFact) } - val mappedRequiredFacts = analysisContext.methodCallFactMapper.mapMethodExitToReturnFlowFact( - currentEdge.statement, requiredFact - ) - - val factInitials = mappedRequiredFacts.flatMapTo(hashSetOf()) { - searcher.findMatchingEdgesInitialFacts(currentEdge.statement, it) - } + val factInitials = searcher.findMatchingEdgesInitialFacts(currentEdge.statement, requiredFact) if (factInitials.isEmpty()) { continue@nextSummary @@ -1248,7 +1317,7 @@ class NormalMethodAnalyzer( summaryHandler.handleZeroToFact( currentEdgeFactAp, EdgeRefinement.UniverseRefinement, - summaryEdge.summaryEdge() + summaryEdge ) } @@ -1258,7 +1327,7 @@ class NormalMethodAnalyzer( initialFact, currentEdgeFactAp, EdgeRefinement.UniverseRefinement, - summaryEdge.summaryEdge() + summaryEdge ) } @@ -1267,7 +1336,7 @@ class NormalMethodAnalyzer( ndSummaryInitial, currentEdgeFactAp, EdgeRefinement.UniverseRefinement, - summaryEdge.summaryEdge() + summaryEdge ) } } @@ -1281,7 +1350,7 @@ class NormalMethodAnalyzer( currentEdge.initialFactAp, currentEdgeFactAp, EdgeRefinement.IdRefinement, - summaryEdge.summaryEdge() + summaryEdge ) } @@ -1290,7 +1359,7 @@ class NormalMethodAnalyzer( ndSummaryInitial, currentEdgeFactAp, EdgeRefinement.UniverseRefinement, - summaryEdge.summaryEdge() + summaryEdge ) } } @@ -1301,7 +1370,7 @@ class NormalMethodAnalyzer( ndSummaryInitial + currentEdge.initialFacts, currentEdgeFactAp, EdgeRefinement.UniverseRefinement, - summaryEdge.summaryEdge() + summaryEdge ) } } @@ -1336,10 +1405,14 @@ class NormalMethodAnalyzer( return resolver.resolveForwardTrace(statement, fact, includeStatement, relevantFactFilter) } - override fun resolveCalleeFact(statement: CommonInst, factAp: FinalFactAp): Set = - analysisContext.methodCallFactMapper.mapMethodExitToReturnFlowFact( - statement, factAp, FactTypeChecker.Dummy - ).toSet() + override fun resolveCalleeFact( + statement: CommonInst, + factAp: FinalFactAp, + callee: MethodEntryPoint, + ): Set = + analysisManager.getMethodCallSummaryHandler(apManager, analysisContext, statement) + .prepareSummaryFinalFact(factAp, callee) + .toSet() private fun updateTaintRulesStats( finalEdgeFact: FinalFactAp?, @@ -1356,8 +1429,7 @@ class NormalMethodAnalyzer( } } - private fun FactToFact.summaryEdge() = SummaryEdge.F2F(initialFactAp, factAp) - private fun NDFactToFact.summaryEdge() = SummaryEdge.NdF2F(initialFacts, factAp) + private fun FactToFact.summaryEdge() = SummaryEdge.F2F(this.methodEntryPoint, initialFactAp, factAp) override fun cleanup() { methodEntryPointsCache = hashMapOf() @@ -1512,7 +1584,7 @@ class EmptyMethodAnalyzer( override fun handleMethodSideEffectRequirement( currentEdge: FactToFact, - methodInitialFactBase: AccessPathBase, + callee: MethodEntryPoint, methodSideEffectRequirements: List ) { error("Empty method should not receive side effect requirements") @@ -1527,6 +1599,7 @@ class EmptyMethodAnalyzer( override fun handleZeroToFactMethodSideEffectSummary( summarySubs: List, + callee: MethodEntryPoint, sideEffectSummaries: List ) { error("Empty method should not receive side effects") @@ -1534,6 +1607,7 @@ class EmptyMethodAnalyzer( override fun handleFactToFactMethodSideEffectSummary( summarySubs: List, + callee: MethodEntryPoint, sideEffectSummaries: List ) { error("Empty method should not receive side effects") @@ -1550,10 +1624,6 @@ class EmptyMethodAnalyzer( error("Empty method should not method resolution results") } - override fun handleResolvedMethodCall(entryPoint: MethodEntryPoint, handler: MethodCallHandler) { - error("Empty method should not method resolution results") - } - override fun handleMethodCallResolutionFailure(callExpr: CommonCallExpr, handler: MethodCallResolutionFailureHandler) { error("Empty method should not method resolution results") } @@ -1571,7 +1641,11 @@ class EmptyMethodAnalyzer( TODO("Not yet implemented") } - override fun resolveCalleeFact(statement: CommonInst, factAp: FinalFactAp): Set { + override fun resolveCalleeFact( + statement: CommonInst, + factAp: FinalFactAp, + callee: MethodEntryPoint, + ): Set { TODO("Not yet implemented") } @@ -1756,13 +1830,13 @@ class TimedMethodAnalyzer( override fun handleMethodSideEffectRequirement( currentEdge: FactToFact, - methodInitialFactBase: AccessPathBase, + callee: MethodEntryPoint, methodSideEffectRequirements: List, ) = timeOperation( operation = "handleMethodSideEffectRequirement", category = OpCategory.SUMMARY, ) { - base.handleMethodSideEffectRequirement(currentEdge, methodInitialFactBase, methodSideEffectRequirements) + base.handleMethodSideEffectRequirement(currentEdge, callee, methodSideEffectRequirements) } override fun handleZeroToZeroMethodSideEffectSummary( @@ -1777,22 +1851,24 @@ class TimedMethodAnalyzer( override fun handleZeroToFactMethodSideEffectSummary( summarySubs: List, + callee: MethodEntryPoint, sideEffectSummaries: List, ) = timeOperation( operation = "handleZeroToFactMethodSideEffectSummary", category = OpCategory.SUMMARY, ) { - base.handleZeroToFactMethodSideEffectSummary(summarySubs, sideEffectSummaries) + base.handleZeroToFactMethodSideEffectSummary(summarySubs, callee, sideEffectSummaries) } override fun handleFactToFactMethodSideEffectSummary( summarySubs: List, + callee: MethodEntryPoint, sideEffectSummaries: List, ) = timeOperation( operation = "handleFactToFactMethodSideEffectSummary", category = OpCategory.SUMMARY, ) { - base.handleFactToFactMethodSideEffectSummary(summarySubs, sideEffectSummaries) + base.handleFactToFactMethodSideEffectSummary(summarySubs, callee, sideEffectSummaries) } override fun handleNDFactToFactMethodSideEffectSummary( @@ -1812,13 +1888,6 @@ class TimedMethodAnalyzer( base.handleResolvedMethodCall(method, handler) } - override fun handleResolvedMethodCall(entryPoint: MethodEntryPoint, handler: MethodCallHandler) = timeOperation( - operation = "handleResolvedMethodCall(entryPoint)", - category = OpCategory.CALL, - ) { - base.handleResolvedMethodCall(entryPoint, handler) - } - override fun handleMethodCallResolutionFailure( callExpr: CommonCallExpr, handler: MethodCallResolutionFailureHandler, @@ -1847,12 +1916,13 @@ class TimedMethodAnalyzer( override fun resolveCalleeFact( statement: CommonInst, factAp: FinalFactAp, + callee: MethodEntryPoint, ): Set = timeOperation( operation = "resolveCalleeFact", category = OpCategory.TRACE, addToTotalTime = false, ) { - base.resolveCalleeFact(statement, factAp) + base.resolveCalleeFact(statement, factAp, callee) } override fun allIntraProceduralFacts(): Map> = timeOperation( diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/MethodAnalyzerEdgeSearcher.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/MethodAnalyzerEdgeSearcher.kt index ae3fa9de5..44352f148 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/MethodAnalyzerEdgeSearcher.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/MethodAnalyzerEdgeSearcher.kt @@ -6,6 +6,7 @@ import org.opentaint.dataflow.ap.ifds.access.InitialFactAp import org.opentaint.dataflow.ap.ifds.analysis.AnalysisManager import org.opentaint.dataflow.ap.ifds.analysis.MethodAnalysisContext import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPrecondition +import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPreconditionFact import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.PreconditionFactsForInitialFact import org.opentaint.dataflow.ap.ifds.trace.MethodSequentPrecondition.SequentPrecondition import org.opentaint.dataflow.ap.ifds.trace.MethodSequentPrecondition.SequentPreconditionFacts diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/SummaryEdgeSubscription.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/SummaryEdgeSubscription.kt index 2b639540b..716514f3a 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/SummaryEdgeSubscription.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/SummaryEdgeSubscription.kt @@ -86,7 +86,7 @@ class SummaryEdgeSubscriptionManager( val calleeInitialFactAp = addedSubscription.callerPathEdge.factAp.rebase(addedSubscription.calleeInitialFactBase) val summaries = manager.findFactSummaryEdges(methodEntryPoint, calleeInitialFactAp) - val sub = ZeroToFactSub(addedSubscription.callerPathEdge, addedSubscription.calleeInitialFactBase) + val sub = ZeroToFactSub(addedSubscription.callerPathEdge) if (summaries.isNotEmpty()) { callerAnalyzer.handleZeroToFactMethodSummaryEdge(listOf(sub), summaries) @@ -101,6 +101,7 @@ class SummaryEdgeSubscriptionManager( if (sideEffectSummaries.isNotEmpty()) { callerAnalyzer.handleZeroToFactMethodSideEffectSummary( listOf(sub), + methodEntryPoint, sideEffectSummaries ) } @@ -121,7 +122,7 @@ class SummaryEdgeSubscriptionManager( val calleeInitialFactAp = addedSubscription.callerPathEdge.factAp.rebase(addedSubscription.calleeInitialFactBase) val summaries = manager.findFactSummaryEdges(methodEntryPoint, calleeInitialFactAp) - val sub = FactToFactSub(addedSubscription.callerPathEdge, addedSubscription.calleeInitialFactBase) + val sub = FactToFactSub(addedSubscription.callerPathEdge) if (summaries.isNotEmpty()) { callerAnalyzer.handleFactToFactMethodSummaryEdge(listOf(sub), summaries) @@ -136,7 +137,7 @@ class SummaryEdgeSubscriptionManager( if (sideEffectRequirements.isNotEmpty()) { callerAnalyzer.handleMethodSideEffectRequirement( addedSubscription.callerPathEdge, - addedSubscription.calleeInitialFactBase, + methodEntryPoint, sideEffectRequirements ) } @@ -145,6 +146,7 @@ class SummaryEdgeSubscriptionManager( if (sideEffectSummaries.isNotEmpty()) { callerAnalyzer.handleFactToFactMethodSideEffectSummary( listOf(sub), + methodEntryPoint, sideEffectSummaries ) } @@ -165,7 +167,7 @@ class SummaryEdgeSubscriptionManager( val calleeInitialFactAp = addedSubscription.callerPathEdge.factAp.rebase(addedSubscription.calleeInitialFactBase) val summaries = manager.findFactSummaryEdges(methodEntryPoint, calleeInitialFactAp) - val sub = NDFactToFactSub(addedSubscription.callerPathEdge, addedSubscription.calleeInitialFactBase) + val sub = NDFactToFactSub(addedSubscription.callerPathEdge) if (summaries.isNotEmpty()) { callerAnalyzer.handleNDFactToFactMethodSummaryEdge(listOf(sub), summaries) @@ -568,7 +570,7 @@ class SummaryEdgeSubscriptionManager( ) { subscriptionStorage.findFactEdgeSub(summaryInitialFact).forEach { (ep, subscriptions) -> val summarySubs = subscriptions.mapTo(mutableListOf()) { - FactToFactSub(it.callerPathEdge, it.calleeInitialFactBase) + FactToFactSub(it.callerPathEdge) } if (summarySubs.isEmpty()) return@forEach @@ -579,7 +581,7 @@ class SummaryEdgeSubscriptionManager( subscriptionStorage.findZeroEdgeSub(summaryInitialFact).forEach { (ep, subscriptions) -> val summarySubs = subscriptions.mapTo(mutableListOf()) { - ZeroToFactSub(it.callerPathEdge, it.calleeInitialFactBase) + ZeroToFactSub(it.callerPathEdge) } if (summarySubs.isEmpty()) return@forEach @@ -590,7 +592,7 @@ class SummaryEdgeSubscriptionManager( subscriptionStorage.findFactNDEdgeSub(summaryInitialFact).forEach { (ep, subscriptions) -> val summarySubs = subscriptions.mapTo(mutableListOf()) { - NDFactToFactSub(it.callerPathEdge, it.calleeInitialFactBase) + NDFactToFactSub(it.callerPathEdge) } if (summarySubs.isEmpty()) return@forEach @@ -634,7 +636,8 @@ class SummaryEdgeSubscriptionManager( val analyzer = processingCtx.getMethodAnalyzer(ep) for (subscription in subscriptions) { analyzer.handleMethodSideEffectRequirement( - subscription.callerPathEdge, subscription.calleeInitialFactBase, + subscription.callerPathEdge, + methodEntryPoint, listOf(sideEffectRequirement) ) } @@ -695,24 +698,24 @@ class SummaryEdgeSubscriptionManager( ) { subscriptionStorage.findFactEdgeSub(seInitialFact).forEach { (ep, subscriptions) -> val summarySubs = subscriptions.mapTo(mutableListOf()) { - FactToFactSub(it.callerPathEdge, it.calleeInitialFactBase) + FactToFactSub(it.callerPathEdge) } if (summarySubs.isEmpty()) return@forEach val analyzer = processingCtx.getMethodAnalyzer(ep) - analyzer.handleFactToFactMethodSideEffectSummary(summarySubs, sideEffects) + analyzer.handleFactToFactMethodSideEffectSummary(summarySubs, methodEntryPoint, sideEffects) } subscriptionStorage.findZeroEdgeSub(seInitialFact).forEach { (ep, subscriptions) -> val summarySubs = subscriptions.mapTo(mutableListOf()) { - ZeroToFactSub(it.callerPathEdge, it.calleeInitialFactBase) + ZeroToFactSub(it.callerPathEdge) } if (summarySubs.isEmpty()) return@forEach val analyzer = processingCtx.getMethodAnalyzer(ep) - analyzer.handleZeroToFactMethodSideEffectSummary(summarySubs, sideEffects) + analyzer.handleZeroToFactMethodSideEffectSummary(summarySubs, methodEntryPoint, sideEffects) } } } diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/TaintAnalysisUnitRunner.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/TaintAnalysisUnitRunner.kt index 3f53301f6..2a6bfcf64 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/TaintAnalysisUnitRunner.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/TaintAnalysisUnitRunner.kt @@ -506,11 +506,12 @@ class TaintAnalysisUnitRunner( fun resolveCalleeFact( methodEntryPoint: MethodEntryPoint, statement: CommonInst, - factAp: FinalFactAp + factAp: FinalFactAp, + callee: MethodEntryPoint, ): Set { val methodRunners = methodAnalyzers(methodEntryPoint) val runner = methodRunners.getAnalyzer(methodEntryPoint) - return runner.resolveCalleeFact(statement, factAp) + return runner.resolveCalleeFact(statement, factAp, callee) } companion object { diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/AnalysisManager.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/AnalysisManager.kt index c11decfd2..eddb2b54b 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/AnalysisManager.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/AnalysisManager.kt @@ -10,6 +10,7 @@ import org.opentaint.dataflow.ap.ifds.TaintAnalysisUnitRunner import org.opentaint.dataflow.ap.ifds.access.ApManager import org.opentaint.dataflow.ap.ifds.access.FinalFactAp import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition +import org.opentaint.dataflow.ap.ifds.trace.MethodCallSummaryPrecondition import org.opentaint.dataflow.ap.ifds.trace.MethodSequentPrecondition import org.opentaint.dataflow.ap.ifds.trace.MethodStartPrecondition import org.opentaint.dataflow.graph.MethodInstGraph @@ -90,6 +91,12 @@ interface AnalysisManager: LanguageManager { statement: CommonInst, ): MethodCallSummaryHandler + fun getMethodCallSummaryPrecondition( + apManager: ApManager, + analysisContext: MethodAnalysisContext, + statement: CommonInst, + ): MethodCallSummaryPrecondition + fun getMethodSideEffectSummaryHandler( apManager: ApManager, analysisContext: MethodAnalysisContext, diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodAnalysisContext.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodAnalysisContext.kt index 29b22f302..731f4e88a 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodAnalysisContext.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodAnalysisContext.kt @@ -4,7 +4,4 @@ import org.opentaint.dataflow.ap.ifds.MethodEntryPoint interface MethodAnalysisContext { val methodEntryPoint: MethodEntryPoint - - // todo: remove, required for trace generation - val methodCallFactMapper: MethodCallFactMapper } diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodCallFlowFunction.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodCallFlowFunction.kt index 6ccd5edd5..d7b6d8a82 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodCallFlowFunction.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodCallFlowFunction.kt @@ -2,6 +2,7 @@ package org.opentaint.dataflow.ap.ifds.analysis import org.opentaint.dataflow.ap.ifds.AccessPathBase import org.opentaint.dataflow.ap.ifds.ExclusionSet +import org.opentaint.dataflow.ap.ifds.MethodWithContext import org.opentaint.dataflow.ap.ifds.SideEffectKind import org.opentaint.dataflow.ap.ifds.access.FinalFactAp import org.opentaint.dataflow.ap.ifds.access.InitialFactAp @@ -26,53 +27,59 @@ interface MethodCallFlowFunction { sealed interface NDFactCallFailureFact: NDFactCallFact + sealed interface ZeroCallSuccessFact + + sealed interface FactCallSuccessFact + + sealed interface NDFactCallSuccessFact + data object Unchanged : ZeroCallFact, FactCallFact, NDFactCallFact - data object CallToReturnZeroFact: ZeroCallFact, Call2ReturnFact, ZeroCallFailureFact + data object CallToReturnZeroFact: ZeroCallFact, Call2ReturnFact, ZeroCallFailureFact, ZeroCallSuccessFact - data object CallToStartZeroFact : ZeroCallFact + data object CallToStartZeroFact : ZeroCallFact, ZeroCallSuccessFact data class CallToReturnFFact( val initialFactAp: InitialFactAp, val factAp: FinalFactAp, val traceInfo: TraceInfo?, - ) : FactCallFact, ZeroCallFact, Call2ReturnFact, FactCallFailureFact, ZeroCallFailureFact + ) : FactCallFact, ZeroCallFact, Call2ReturnFact, FactCallFailureFact, ZeroCallFailureFact, ZeroCallSuccessFact, FactCallSuccessFact data class CallToStartFFact( val initialFactAp: InitialFactAp, val callerFactAp: FinalFactAp, val startFactBase: AccessPathBase, val traceInfo: TraceInfo?, - ) : FactCallFact + ) : FactCallFact, FactCallSuccessFact data class CallToReturnZFact( val factAp: FinalFactAp, val traceInfo: TraceInfo?, - ) : ZeroCallFact, FactCallFact, NDFactCallFact, Call2ReturnFact, ZeroCallFailureFact, FactCallFailureFact, NDFactCallFailureFact + ) : ZeroCallFact, FactCallFact, NDFactCallFact, Call2ReturnFact, ZeroCallFailureFact, FactCallFailureFact, NDFactCallFailureFact, ZeroCallSuccessFact, FactCallSuccessFact, NDFactCallSuccessFact data class CallToStartZFact( val callerFactAp: FinalFactAp, val startFactBase: AccessPathBase, val traceInfo: TraceInfo?, - ) : ZeroCallFact + ) : ZeroCallFact, ZeroCallSuccessFact data class CallToReturnNonDistributiveFact( val initialFacts: Set, val factAp: FinalFactAp, val traceInfo: TraceInfo?, - ) : FactCallFact, ZeroCallFact, NDFactCallFact, Call2ReturnFact, FactCallFailureFact, ZeroCallFailureFact, NDFactCallFailureFact + ) : FactCallFact, ZeroCallFact, NDFactCallFact, Call2ReturnFact, FactCallFailureFact, ZeroCallFailureFact, NDFactCallFailureFact, ZeroCallSuccessFact, FactCallSuccessFact, NDFactCallSuccessFact data class CallToStartNDFFact( val initialFacts: Set, val callerFactAp: FinalFactAp, val startFactBase: AccessPathBase, val traceInfo: TraceInfo?, - ) : NDFactCallFact + ) : NDFactCallFact, NDFactCallSuccessFact - data class SideEffectRequirement(val initialFactAp: InitialFactAp) : FactCallFact, FactCallFailureFact + data class SideEffectRequirement(val initialFactAp: InitialFactAp) : FactCallFact, FactCallFailureFact, FactCallSuccessFact data class ZeroSideEffect(val kind: SideEffectKind) : ZeroCallFact, ZeroCallFailureFact - data class FactSideEffect(val initialFactAp: InitialFactAp, val kind: SideEffectKind) : FactCallFact, FactCallFailureFact + data class FactSideEffect(val initialFactAp: InitialFactAp, val kind: SideEffectKind) : FactCallFact, FactCallFailureFact, FactCallSuccessFact data class Drop( val traceInfo: TraceInfo?, @@ -93,6 +100,11 @@ interface MethodCallFlowFunction { fun propagateFactToFactResolutionFailure(initialFactAp: InitialFactAp, currentFactAp: FinalFactAp, startFactBase: AccessPathBase): Set fun propagateNDFactToFactResolutionFailure(initialFacts: Set, currentFactAp: FinalFactAp, startFactBase: AccessPathBase): Set + fun propagateZeroToZeroResolutionSuccess(method: MethodWithContext): Set + fun propagateZeroToFactResolutionSuccess(currentFactAp: FinalFactAp, startFactBase: AccessPathBase, method: MethodWithContext): Set + fun propagateFactToFactResolutionSuccess(initialFactAp: InitialFactAp, currentFactAp: FinalFactAp, startFactBase: AccessPathBase, method: MethodWithContext): Set + fun propagateNDFactToFactResolutionSuccess(initialFacts: Set, currentFactAp: FinalFactAp, startFactBase: AccessPathBase, method: MethodWithContext): Set + interface Default : MethodCallFlowFunction { override fun propagateZeroToFact(currentFactAp: FinalFactAp) = buildSet { propagateFact( @@ -187,6 +199,7 @@ interface MethodCallFlowFunction { override fun propagateZeroToFactResolutionFailure(currentFactAp: FinalFactAp, startFactBase: AccessPathBase) = buildSet { propagateUnresolvedCallFact( factAp = currentFactAp, + startFactBase = startFactBase, addSideEffectRequirement = { factReader -> check(!factReader.hasRefinement) { "Can't refine Zero fact" } }, @@ -204,6 +217,7 @@ interface MethodCallFlowFunction { ): Set = buildSet { propagateUnresolvedCallFact( factAp = currentFactAp, + startFactBase = startFactBase, addSideEffectRequirement = { factReader -> this += SideEffectRequirement(factReader.refineFact(initialFactAp.replaceExclusions(ExclusionSet.Empty))) }, @@ -224,6 +238,7 @@ interface MethodCallFlowFunction { ) = buildSet { propagateUnresolvedCallFact( factAp = currentFactAp, + startFactBase = startFactBase, addSideEffectRequirement = { factReader -> check(!factReader.hasRefinement) { "Can't refine NDF2F edge" } }, @@ -234,6 +249,92 @@ interface MethodCallFlowFunction { ) } + override fun propagateZeroToZeroResolutionSuccess(method: MethodWithContext): Set = + setOf(CallToStartZeroFact) + + override fun propagateZeroToFactResolutionSuccess( + currentFactAp: FinalFactAp, + startFactBase: AccessPathBase, + method: MethodWithContext, + ): Set = buildSet { + propagateSuccessCallFact( + factAp = currentFactAp, + startFactBase = startFactBase, + method = method, + addSideEffectRequirement = { factReader -> + check(!factReader.hasRefinement) { "Can't refine Zero fact" } + }, + addCallToReturn = { factReader, factAp, trace -> + check(!factReader.hasRefinement) { "Can't refine Zero fact" } + this += CallToReturnZFact(factAp, trace) + }, + addCallToStart = { callerFactAp, startFactBase, trace -> + this += CallToStartZFact(callerFactAp, startFactBase, trace) + }, + addUnchecked = { + check(it is ZeroCallSuccessFact) { "unexpected" } + this += it + }, + ) + } + + override fun propagateFactToFactResolutionSuccess( + initialFactAp: InitialFactAp, + currentFactAp: FinalFactAp, + startFactBase: AccessPathBase, + method: MethodWithContext, + ): Set = buildSet { + propagateSuccessCallFact( + factAp = currentFactAp, + startFactBase = startFactBase, + method = method, + addSideEffectRequirement = { factReader -> + this += SideEffectRequirement(factReader.refineFact(initialFactAp.replaceExclusions(ExclusionSet.Empty))) + }, + addCallToReturn = { factReader, factAp, trace -> + this += CallToReturnFFact( + factReader.refineFact(initialFactAp), + factReader.refineFact(factAp), + trace + ) + }, + addCallToStart = { callerFactAp, startFactBase, trace -> + this += CallToStartFFact(initialFactAp, callerFactAp, startFactBase, trace) + }, + addUnchecked = { + check(it is FactCallSuccessFact) { "unexpected" } + this += it + }, + ) + } + + override fun propagateNDFactToFactResolutionSuccess( + initialFacts: Set, + currentFactAp: FinalFactAp, + startFactBase: AccessPathBase, + method: MethodWithContext, + ): Set = buildSet { + propagateSuccessCallFact( + factAp = currentFactAp, + startFactBase = startFactBase, + method = method, + addSideEffectRequirement = { factReader -> + check(!factReader.hasRefinement) { "Can't refine NDF2F edge" } + }, + addCallToReturn = { factReader, factAp, trace -> + check(!factReader.hasRefinement) { "Can't refine NDF2F edge" } + this += CallToReturnNonDistributiveFact(initialFacts, factAp, trace) + }, + addCallToStart = { callerFactAp, startFactBase, trace -> + this += CallToStartNDFFact(initialFacts, callerFactAp, startFactBase, trace) + }, + addUnchecked = { + check(it is NDFactCallSuccessFact) { "unexpected" } + this += it + }, + ) + } + fun propagateFact( initialFacts: Set, exclusion: ExclusionSet, @@ -247,8 +348,19 @@ interface MethodCallFlowFunction { fun propagateUnresolvedCallFact( factAp: FinalFactAp, + startFactBase: AccessPathBase, addCallToReturn: (FinalFactReader, FinalFactAp, TraceInfo?) -> Unit, addSideEffectRequirement: (FinalFactReader) -> Unit, ) + + fun propagateSuccessCallFact( + factAp: FinalFactAp, + startFactBase: AccessPathBase, + method: MethodWithContext, + addSideEffectRequirement: (FinalFactReader) -> Unit, + addCallToReturn: (FinalFactReader, FinalFactAp, TraceInfo?) -> Unit, + addCallToStart: (callerFact: FinalFactAp, startFactBase: AccessPathBase, TraceInfo?) -> Unit, + addUnchecked: (CallFact) -> Unit, + ) } } diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodCallSummaryHandler.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodCallSummaryHandler.kt index 4aa86070d..48340146c 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodCallSummaryHandler.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodCallSummaryHandler.kt @@ -3,6 +3,7 @@ package org.opentaint.dataflow.ap.ifds.analysis import org.opentaint.dataflow.ap.ifds.Edge import org.opentaint.dataflow.ap.ifds.ExclusionSet import org.opentaint.dataflow.ap.ifds.FactTypeChecker +import org.opentaint.dataflow.ap.ifds.MethodEntryPoint import org.opentaint.dataflow.ap.ifds.MethodSummaryEdgeApplicationUtils.EdgeRefinement import org.opentaint.dataflow.ap.ifds.MethodSummaryEdgeApplicationUtils.SummaryEdgeApplication import org.opentaint.dataflow.ap.ifds.MethodSummaryEdgeApplicationUtils.SummaryEdgeApplication.SummaryApRefinement @@ -11,25 +12,42 @@ import org.opentaint.dataflow.ap.ifds.access.FinalFactAp import org.opentaint.dataflow.ap.ifds.access.InitialFactAp import org.opentaint.dataflow.ap.ifds.analysis.MethodSequentFlowFunction.Sequent import org.opentaint.dataflow.ap.ifds.analysis.MethodSequentFlowFunction.TraceInfo +import org.opentaint.dataflow.util.cartesianProductMapTo interface MethodCallSummaryHandler { val factTypeChecker: FactTypeChecker sealed interface SummaryEdge { + val methodEntryPoint: MethodEntryPoint val final: FinalFactAp - data class F2F(val initial: InitialFactAp, override val final: FinalFactAp) : SummaryEdge - data class NdF2F(val initial: Set, override val final: FinalFactAp) : SummaryEdge + data class F2F( + override val methodEntryPoint: MethodEntryPoint, + val initial: InitialFactAp, + override val final: FinalFactAp, + ) : SummaryEdge + + data class NdF2F( + override val methodEntryPoint: MethodEntryPoint, + val initial: Set, + override val final: FinalFactAp, + ) : SummaryEdge } - fun mapMethodExitToReturnFlowFact(fact: FinalFactAp): List + fun prepareSummaryInitialFact(fact: InitialFactAp, callee: MethodEntryPoint): List + + fun prepareSummaryFinalFact(fact: FinalFactAp, callee: MethodEntryPoint): List fun handleZeroToZero(summaryFact: FinalFactAp?): Set { if (summaryFact == null) return setOf(Sequent.ZeroToZero) - val summaryExitFacts = mapMethodExitToReturnFlowFact(summaryFact) - return summaryExitFacts.mapTo(hashSetOf()) { - Sequent.ZeroToFact(it, TraceInfo.ApplySummary) + return setOf(Sequent.ZeroToFact(summaryFact, TraceInfo.ApplySummary)) + } + + fun prepareZeroToFactSummary(summaryEdge: Edge.ZeroToFact): List { + val callee = summaryEdge.methodEntryPoint + return prepareSummaryFinalFact(summaryEdge.factAp, callee).map { + Edge.ZeroToFact(callee, summaryEdge.statement, it) } } @@ -69,7 +87,15 @@ interface MethodCallSummaryHandler { Sequent.FactToFact(initialFactAp.refine(initialFactRefinement), summaryFactAp, TraceInfo.ApplySummary) } - fun prepareFactToFactSummary(summaryEdge: Edge.FactToFact): List = listOf(summaryEdge) + fun prepareFactToFactSummary(summaryEdge: Edge.FactToFact): List { + val callee = summaryEdge.methodEntryPoint + val finalFacts = prepareSummaryFinalFact(summaryEdge.factAp, callee) + return prepareSummaryInitialFact(summaryEdge.initialFactAp, callee).flatMap { initialFactAp -> + finalFacts.map { factAp -> + Edge.FactToFact(callee, initialFactAp, summaryEdge.statement, factAp) + } + } + } fun handleNDFactToFact( initialFacts: Set, @@ -96,7 +122,18 @@ interface MethodCallSummaryHandler { ) } - fun prepareNDFactToFactSummary(summaryEdge: Edge.NDFactToFact): List = listOf(summaryEdge) + fun prepareNDFactToFactSummary(summaryEdge: Edge.NDFactToFact): List { + val callee = summaryEdge.methodEntryPoint + val finalFacts = prepareSummaryFinalFact(summaryEdge.factAp, callee) + return summaryEdge.initialFacts + .map { prepareSummaryInitialFact(it, callee) } + .cartesianProductMapTo { it.toHashSet() } + .flatMap { initialFacts -> + finalFacts.map { factAp -> + SummaryEdge.NdF2F(callee, initialFacts, factAp) + } + } + } fun InitialFactAp.refine(exclusionSet: ExclusionSet?) = if (exclusionSet == null) this else replaceExclusions(exclusionSet) @@ -108,35 +145,40 @@ interface MethodCallSummaryHandler { createSideEffectRequirement: (refinement: ExclusionSet) -> Sequent?, handleSummaryEdge: (initialFactRefinement: ExclusionSet?, summaryFactAp: FinalFactAp) -> Sequent ): Set { - val mappedSummaryFacts = mapMethodExitToReturnFlowFact(summaryEdge.final) + val summaryFinalFact = summaryEdge.final return when (summaryEffect) { - is SummaryEdgeApplication -> mappedSummaryFacts.mapNotNullTo(hashSetOf()) { mappedSummaryFact -> - val summaryFactAp = mappedSummaryFact - .concat(factTypeChecker, summaryEffect.delta) - ?: return@mapNotNullTo null + is SummaryEdgeApplication -> { + val summaryFactAp = summaryFinalFact.concat(factTypeChecker, summaryEffect.delta) + ?: return emptySet() when (summaryEffect) { is SummaryApRefinement -> { // todo: filter exclusions val fact = summaryFactAp.replaceExclusions(currentFactAp.exclusions) - handleSummaryEdge(null, fact) + setOf(handleSummaryEdge(null, fact)) } is SummaryExclusionRefinement -> { val fact = summaryFactAp.replaceExclusions(summaryEffect.exclusion) - handleSummaryEdge(summaryEffect.exclusion, fact) + setOf(handleSummaryEdge(summaryEffect.exclusion, fact)) } } } - is EdgeRefinement.UniverseRefinement -> mappedSummaryFacts.mapTo(hashSetOf()) { - handleSummaryEdge(ExclusionSet.Universe, it.replaceExclusions(ExclusionSet.Universe)) - } - - is EdgeRefinement.IdRefinement -> mappedSummaryFacts.mapTo(hashSetOf()) { - handleSummaryEdge(currentFactAp.exclusions, it.replaceExclusions(currentFactAp.exclusions)) - } + is EdgeRefinement.UniverseRefinement -> setOf( + handleSummaryEdge( + ExclusionSet.Universe, + summaryFinalFact.replaceExclusions(ExclusionSet.Universe) + ) + ) + + is EdgeRefinement.IdRefinement -> setOf( + handleSummaryEdge( + currentFactAp.exclusions, + summaryFinalFact.replaceExclusions(currentFactAp.exclusions) + ) + ) } } } diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodSideEffectSummaryHandler.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodSideEffectSummaryHandler.kt index e444138d4..14ab9371a 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodSideEffectSummaryHandler.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/analysis/MethodSideEffectSummaryHandler.kt @@ -1,6 +1,7 @@ package org.opentaint.dataflow.ap.ifds.analysis import org.opentaint.dataflow.ap.ifds.ExclusionSet +import org.opentaint.dataflow.ap.ifds.MethodEntryPoint import org.opentaint.dataflow.ap.ifds.MethodSummaryEdgeApplicationUtils.SummaryEdgeApplication import org.opentaint.dataflow.ap.ifds.MethodSummaryEdgeApplicationUtils.SummaryEdgeApplication.SummaryApRefinement import org.opentaint.dataflow.ap.ifds.MethodSummaryEdgeApplicationUtils.SummaryEdgeApplication.SummaryExclusionRefinement diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodCallPrecondition.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodCallPrecondition.kt index 71c1efda6..2e1b11261 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodCallPrecondition.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodCallPrecondition.kt @@ -2,10 +2,11 @@ package org.opentaint.dataflow.ap.ifds.trace import org.opentaint.dataflow.ap.ifds.AccessPathBase import org.opentaint.dataflow.ap.ifds.MethodAnalyzerEdges +import org.opentaint.dataflow.ap.ifds.MethodWithContext import org.opentaint.dataflow.ap.ifds.access.ApManager import org.opentaint.dataflow.ap.ifds.access.FinalFactAp import org.opentaint.dataflow.ap.ifds.access.InitialFactAp -import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPreconditionFact.CallFailurePreconditionFact +import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPrecondition import org.opentaint.dataflow.ap.ifds.trace.TaintRulePrecondition.PassRuleCondition import org.opentaint.dataflow.taint.PreconditionCube import org.opentaint.dataflow.taint.TaintMarkAwareConditionExpr @@ -22,16 +23,20 @@ interface MethodCallPrecondition { val preconditionFacts: List, ): CallPrecondition - sealed interface CallPreconditionFact { - sealed interface CallFailurePreconditionFact : CallPreconditionFact + sealed interface CallPreconditionFact + sealed interface CallResolutionPreconditionFact - object UnresolvedCallSkip : CallPreconditionFact, CallFailurePreconditionFact - data class CallToReturnTaintRule(val precondition: TaintRulePrecondition) : CallPreconditionFact, CallFailurePreconditionFact - data class CallToStart(val callerFact: InitialFactAp, val startFactBase: AccessPathBase) : CallPreconditionFact - } + sealed interface CallFailurePreconditionFact : CallResolutionPreconditionFact + sealed interface CallSuccessPreconditionFact : CallResolutionPreconditionFact + + object UnresolvedCallSkip : CallPreconditionFact, CallFailurePreconditionFact + data class CallToReturnTaintRule(val precondition: TaintRulePrecondition) : CallPreconditionFact, CallFailurePreconditionFact, CallSuccessPreconditionFact + data class CallToStart(val callerFact: InitialFactAp, val startFactBase: AccessPathBase) : CallPreconditionFact + data class CallToStartResolved(val callerFact: InitialFactAp, val startFactBase: AccessPathBase, val method: MethodWithContext): CallSuccessPreconditionFact fun factPrecondition(fact: InitialFactAp): List fun factPreconditionResolutionFailure(fact: InitialFactAp, startFactBase: AccessPathBase): List + fun factPreconditionResolutionSuccess(fact: InitialFactAp, startFactBase: AccessPathBase, method: MethodWithContext): List data class PassRuleConditionFacts(val facts: List) @@ -79,3 +84,4 @@ interface MethodCallPrecondition { preconditionDnf(apManager, { allRelevantFacts(edges, it) }) { mapExit2Return(it) } } } + diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodCallSummaryPrecondition.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodCallSummaryPrecondition.kt new file mode 100644 index 000000000..c2e1e0587 --- /dev/null +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodCallSummaryPrecondition.kt @@ -0,0 +1,8 @@ +package org.opentaint.dataflow.ap.ifds.trace + +import org.opentaint.dataflow.ap.ifds.MethodEntryPoint +import org.opentaint.dataflow.ap.ifds.access.InitialFactAp + +interface MethodCallSummaryPrecondition { + fun callSummaryPrecondition(fact: InitialFactAp, callee: MethodEntryPoint): List +} diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodForwardTraceResolver.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodForwardTraceResolver.kt index 0044b79e4..02cb41298 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodForwardTraceResolver.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodForwardTraceResolver.kt @@ -264,16 +264,17 @@ class MethodForwardTraceResolver( val calleeInitialFactAp = callerEdge.factAp.rebase(startFactBase) val summaries = manager.findFactSummaryEdges(ep, calleeInitialFactAp) - val applicableSummaries = summaries.filter { isApplicableExitToReturnEdge(it) } - val handler = analysisManager.getMethodCallSummaryHandler( apManager, analysisContext, callerEdge.statement ) + val applicableSummaries = summaries + .filter { isApplicableExitToReturnEdge(it) } + .flatMap { handler.prepareFactToFactSummary(it) } + val summaryApplied = applyMethodSummaries( currentEdge = callerEdge, callerFact = callerFact, - methodInitialFactBase = startFactBase, methodSummaries = applicableSummaries, handleSummaryEdge = handler::handleZeroToFact ) @@ -292,22 +293,22 @@ class MethodForwardTraceResolver( private fun TraceBuilder.applyMethodSummaries( currentEdge: ZeroToFact, callerFact: FinalFactAp, - methodInitialFactBase: AccessPathBase, methodSummaries: List, handleSummaryEdge: (currentFactAp: FinalFactAp, summaryEffect: SummaryEdgeApplication, summaryEdge: SummaryEdge) -> Set, ): Boolean { var summaryApplied = false - val methodInitialFact = callerFact.rebase(methodInitialFactBase) val summaries = methodSummaries.groupByTo(hashMapOf()) { it.initialFactAp } for ((summaryInitialFact, summaryEdges) in summaries) { val summaryEdgeEffects = MethodSummaryEdgeApplicationUtils.tryApplySummaryEdge( - methodInitialFact, summaryInitialFact + callerFact, summaryInitialFact ) for (summaryEdgeEffect in summaryEdgeEffects) { for (methodSummary in summaryEdges) { - val summaryEdge = SummaryEdge.F2F(methodSummary.initialFactAp, methodSummary.factAp) + val summaryEdge = SummaryEdge.F2F( + methodSummary.methodEntryPoint, methodSummary.initialFactAp, methodSummary.factAp + ) val sf = handleSummaryEdge(callerFact, summaryEdgeEffect, summaryEdge) handleSequentFact(currentEdge, sf) summaryApplied = true diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodTraceResolver.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodTraceResolver.kt index 06d5386eb..7b77075e1 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodTraceResolver.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/MethodTraceResolver.kt @@ -20,10 +20,11 @@ import org.opentaint.dataflow.ap.ifds.access.FinalFactAp import org.opentaint.dataflow.ap.ifds.access.InitialFactAp import org.opentaint.dataflow.ap.ifds.analysis.AnalysisManager import org.opentaint.dataflow.ap.ifds.analysis.MethodAnalysisContext -import org.opentaint.dataflow.ap.ifds.analysis.MethodCallFactMapper import org.opentaint.dataflow.ap.ifds.analysis.MethodCallResolver.MethodCallResolutionResult import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPrecondition +import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallResolutionPreconditionFact import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPreconditionFact +import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.PreconditionFactsForInitialFact import org.opentaint.dataflow.ap.ifds.trace.MethodSequentPrecondition.SequentPrecondition import org.opentaint.dataflow.ap.ifds.trace.MethodTraceResolver.PartiallyResolvedMergedCallAction.MergedPrimaryCall2StartAction import org.opentaint.dataflow.ap.ifds.trace.MethodTraceResolver.PartiallyResolvedMergedCallAction.MergedPrimaryUnresolvedCallSkip @@ -63,6 +64,7 @@ import org.opentaint.ir.api.common.cfg.CommonValue import java.util.BitSet import java.util.LinkedList import java.util.Objects +import kotlin.collections.plusAssign class MethodTraceResolver( private val runner: AnalysisRunner, @@ -74,7 +76,6 @@ class MethodTraceResolver( private val methodEntryPoint: MethodEntryPoint = analysisContext.methodEntryPoint private val analysisManager: AnalysisManager get() = runner.analysisManager private val manager: AnalysisUnitRunnerManager get() = runner.manager - private val methodCallFactMapper: MethodCallFactMapper get() = analysisContext.methodCallFactMapper private val apManager: ApManager get() = runner.apManager // Enum can give non-determinacy as its entries have new hash code on every JVM run. @@ -449,8 +450,9 @@ class MethodTraceResolver( statement: CommonInst, calleeEntry: TraceEntry.MethodEntry ): List { + val handler = analysisManager.getMethodCallSummaryPrecondition(apManager, analysisContext, statement) val traceEdges = calleeEntry.facts.flatMap { fact -> - val mappedFacts = methodCallFactMapper.mapMethodExitToReturnFlowFact(statement, fact) + val mappedFacts = handler.callSummaryPrecondition(fact, calleeEntry.entryPoint) mappedFacts.map { resolveIntraProceduralTraceEdge(statement, it, includeStatement = false) } } @@ -890,20 +892,17 @@ class MethodTraceResolver( val preconditionFunction = analysisManager.getMethodCallPrecondition( apManager, analysisContext, returnValue, statementCall, statement ) - val callees by lazy { - runner.methodCallResolver.resolvedMethodCalls(analysisContext, statementCall, statement) - } val callEdges = mutableListOf>>() for (edge in entry.edges) { - val preconditions = callFactPrecondition(preconditionFunction, edge.fact, callees) + val preconditions = preconditionFunction.factPrecondition(edge.fact) val callActions = mutableListOf>() for (precondition in preconditions) { when (precondition) { is CallPrecondition.Unchanged -> callActions += ActionOrUnchanged.Unchanged(edge) - is MethodCallPrecondition.PreconditionFactsForInitialFact -> { + is PreconditionFactsForInitialFact -> { val initialEdge = edge.replaceFact(precondition.initialFact) if (!skipFactCheck && !containsEntryEdge(entry.statement, initialEdge)) { continue @@ -933,16 +932,11 @@ class MethodTraceResolver( } val resolvedMethods by lazy { - callees.mapNotNull { - when (it) { - is MethodCallResolutionResult.ResolvedMethod -> it.method - MethodCallResolutionResult.ResolutionFailure -> null - } - } + runner.methodCallResolver.resolvedMethodCalls(analysisContext, statementCall, statement) } val resolvedCallActions = mutableListOf() - forEachMergedCallActionsCombination(callEdges, resolvedMethods) { callAction -> + forEachMergedCallActionsCombination(callEdges, preconditionFunction, { resolvedMethods }) { callAction -> resolvedCallActions.resolveCallAction(preconditionFunction, statement, callAction) } @@ -1009,54 +1003,6 @@ class MethodTraceResolver( } } - private fun callFactPrecondition( - preconditionFunction: MethodCallPrecondition, - fact: InitialFactAp, - callees: List, - ): List = buildList { - val preconditions = preconditionFunction.factPrecondition(fact) - - preconditions.forEach { precondition -> - when (precondition) { - CallPrecondition.Unchanged -> { - this += precondition - } - - is MethodCallPrecondition.PreconditionFactsForInitialFact -> { - this += processCallPreconditionFacts(preconditionFunction, precondition, callees) - } - } - } - } - - private fun processCallPreconditionFacts( - preconditionFunction: MethodCallPrecondition, - precondition: MethodCallPrecondition.PreconditionFactsForInitialFact, - callees: List, - ): MethodCallPrecondition.PreconditionFactsForInitialFact { - val resolutionFailure by lazy { callees.any { it is MethodCallResolutionResult.ResolutionFailure } } - - val processedPreconditions = precondition.preconditionFacts.flatMapTo(hashSetOf()) { preconditionFact -> - when (preconditionFact) { - is CallPreconditionFact.UnresolvedCallSkip -> listOf(preconditionFact) - is CallPreconditionFact.CallToReturnTaintRule -> listOf(preconditionFact) - - is CallPreconditionFact.CallToStart -> { - if (resolutionFailure) { - preconditionFunction.factPreconditionResolutionFailure( - precondition.initialFact, - preconditionFact.startFactBase - ) + preconditionFact - } else { - listOf(preconditionFact) - } - } - } - }.toList() - - return MethodCallPrecondition.PreconditionFactsForInitialFact(precondition.initialFact, processedPreconditions) - } - private fun TraceBuilder.addPredecessorActions( actionsCombination: List, entry: TraceEntry, @@ -1181,23 +1127,128 @@ class MethodTraceResolver( private inline fun forEachMergedCallActionsCombination( callActions: List>>, - callees: List, + preconditionFunction: MethodCallPrecondition, + callees: () -> List, body: (PartialCallEdgeCombination) -> Unit, ) { callActions.forEachCartesianProduct { actions -> - val mergedActions = mergeCallActions(actions) { callees } - mergedActions.forEach(body) + resolveCall2StartActions(actions, preconditionFunction, callees) { boundActions -> + boundActions.forEachCartesianProduct { resolvedActions -> + val mergedActions = mergeCallActions(resolvedActions) + mergedActions.forEach(body) + } + } + } + } + + private inline fun resolveCall2StartActions( + actions: Array>, + preconditionFunction: MethodCallPrecondition, + callees: () -> List, + process: (List>>) -> Unit, + ) { + val methodResolutionIsRequired = actions.any { it is ActionOrUnchanged.Action && it.action is PartiallyResolvedCallAction.Call2Start } + + if (!methodResolutionIsRequired) { + process(resolveCall2StartNoCalls(actions)) + return + } + + val resolvedCallees = callees() + resolvedCallees.forEach { callee -> + when (callee) { + is MethodCallResolutionResult.ResolutionFailure -> { + val expandedActions = resolveCall2StartFailure(actions, preconditionFunction) + process(expandedActions) + } + + is MethodCallResolutionResult.ResolvedMethod -> { + val expandedActions = resolveCall2StartSuccess(actions, preconditionFunction, callee.method) + process(expandedActions) + } + } + } + } + + private fun resolveCall2StartSuccess( + actions: Array>, + preconditionFunction: MethodCallPrecondition, + method: MethodWithContext + ): List>> = resolveCall2StartActions(actions) { callerFact, base -> + preconditionFunction.factPreconditionResolutionSuccess(callerFact, base, method) + } + + private fun resolveCall2StartFailure( + actions: Array>, + preconditionFunction: MethodCallPrecondition, + ): List>> = resolveCall2StartActions(actions) { callerFact, base -> + preconditionFunction.factPreconditionResolutionFailure(callerFact, base) + } + + private fun resolveCall2StartNoCalls( + actions: Array> + ): List>> = resolveCall2StartActions(actions) { _, _ -> + error("Unexpected call") + } + + @Suppress("UNCHECKED_CAST") + private inline fun resolveCall2StartActions( + actions: Array>, + call2StartPreconditions: (InitialFactAp, AccessPathBase) -> List, + ): List>> { + return actions.map { action -> + when (action) { + is ActionOrUnchanged.Unchanged -> listOf(action as ActionOrUnchanged.Unchanged) + + is ActionOrUnchanged.Action -> { + collectToListWithPostProcess( + mutableListOf(), + { it.resolveCall2StartAction(action.action, call2StartPreconditions) }, + { ActionOrUnchanged.Action(it) } + ) + } + } + } + } + + private inline fun MutableList.resolveCall2StartAction( + action: PartiallyResolvedCallAction, + call2StartPreconditions: (InitialFactAp, AccessPathBase) -> List, + ) { + val currentEdge = action.currentEdge + + when (action) { + is PartiallyResolvedCallAction.CallRule -> this += PartiallyResolvedBoundCallAction.CallRule(currentEdge, action.rule) + + is PartiallyResolvedCallAction.UnresolvedCallSkip -> this += PartiallyResolvedBoundCallAction.UnresolvedCallSkip(currentEdge) + + is PartiallyResolvedCallAction.Call2Start -> { + call2StartPreconditions(action.call2Start.callerFact, action.call2Start.startFactBase).forEach { fact -> + when (fact) { + is MethodCallPrecondition.UnresolvedCallSkip -> this += PartiallyResolvedBoundCallAction.UnresolvedCallSkip(currentEdge) + + is MethodCallPrecondition.CallToReturnTaintRule -> { + if (skipRulePropagation(fact, currentEdge)) return@forEach + + this += PartiallyResolvedBoundCallAction.CallRule(currentEdge, fact.precondition) + } + + is MethodCallPrecondition.CallToStartResolved -> { + this += PartiallyResolvedBoundCallAction.Call2Start(currentEdge, fact) + } + } + } + } } } private fun mergeCallActions( - aouGroup: Array>, - resolveMethodCallees: () -> List + aouGroup: Array>, ): List { val unchanged = hashSetOf() - val rules = hashSetOf() - val summary = hashSetOf() - val unresolvedSkips = hashSetOf() + val rules = hashSetOf() + val summary = hashSetOf() + val unresolvedSkips = hashSetOf() for (aou in aouGroup) { when (aou) { @@ -1206,9 +1257,9 @@ class MethodTraceResolver( } is ActionOrUnchanged.Action -> when (val action = aou.action) { - is PartiallyResolvedCallAction.CallRule -> rules.add(action) - is PartiallyResolvedCallAction.Call2Start -> summary.add(action) - is PartiallyResolvedCallAction.UnresolvedCallSkip -> { unresolvedSkips.add(action) } + is PartiallyResolvedBoundCallAction.CallRule -> rules.add(action) + is PartiallyResolvedBoundCallAction.Call2Start -> summary.add(action) + is PartiallyResolvedBoundCallAction.UnresolvedCallSkip -> { unresolvedSkips.add(action) } } } } @@ -1230,20 +1281,18 @@ class MethodTraceResolver( return emptyList() } - val callees = resolveMethodCallees() - + // all summaries have the same method + val method = summary.first().call2Start.method val result = mutableListOf() - callees.forEach { callee -> - methodEntryPoints(callee).forEach { - val primary = MergedPrimaryCall2StartAction(it, summary) - result += PartialCallEdgeCombination(unchanged, primary, mergedRules) - } + for (ep in methodEntryPoints(method)) { + val primary = MergedPrimaryCall2StartAction(ep, summary) + result += PartialCallEdgeCombination(unchanged, primary, mergedRules) } return result } - private fun mergeCallRules(callRules: HashSet): Set { + private fun mergeCallRules(callRules: HashSet): Set { if (callRules.isEmpty()) return emptySet() val sourceRules = hashMapOf>>() @@ -1281,27 +1330,45 @@ class MethodTraceResolver( } private sealed interface PartiallyResolvedCallAction { + val currentEdge: TraceEdge + data class CallRule( - val currentEdge: TraceEdge, + override val currentEdge: TraceEdge, val rule: TaintRulePrecondition ) : PartiallyResolvedCallAction data class Call2Start( - val currentEdge: TraceEdge, - val call2Start: CallPreconditionFact.CallToStart, + override val currentEdge: TraceEdge, + val call2Start: MethodCallPrecondition.CallToStart, ): PartiallyResolvedCallAction data class UnresolvedCallSkip( - val currentEdge: TraceEdge, + override val currentEdge: TraceEdge, ): PartiallyResolvedCallAction } + private sealed interface PartiallyResolvedBoundCallAction { + data class CallRule( + val currentEdge: TraceEdge, + val rule: TaintRulePrecondition + ) : PartiallyResolvedBoundCallAction + + data class Call2Start( + val currentEdge: TraceEdge, + val call2Start: MethodCallPrecondition.CallToStartResolved, + ): PartiallyResolvedBoundCallAction + + data class UnresolvedCallSkip( + val currentEdge: TraceEdge, + ): PartiallyResolvedBoundCallAction + } + private sealed interface PartiallyResolvedMergedCallAction { sealed interface PartiallyResolvedMergedPrimaryCallAction: PartiallyResolvedMergedCallAction data class MergedPrimaryCall2StartAction( val calleeEntryPoint: MethodEntryPoint, - val call2Start: Set, + val call2Start: Set, ) : PartiallyResolvedMergedPrimaryCallAction data class MergedPrimaryUnresolvedCallSkip( @@ -1314,26 +1381,27 @@ class MethodTraceResolver( ) : PartiallyResolvedMergedCallAction } + private fun skipRulePropagation(fact: MethodCallPrecondition.CallToReturnTaintRule, currentEdge: TraceEdge) = + // We search for pass-rule, not source rule + fact.precondition is TaintRulePrecondition.Source && currentEdge !is TraceEdge.SourceTraceEdge + private fun MutableList.propagateCall( currentEdge: TraceEdge, - preconditionFacts: List + preconditionFacts: List, ) { for (fact in preconditionFacts) { when (fact) { - is CallPreconditionFact.CallToReturnTaintRule -> { - if (fact.precondition is TaintRulePrecondition.Source && currentEdge !is TraceEdge.SourceTraceEdge) { - // We search for pass-rule, not source rule - continue - } + is MethodCallPrecondition.CallToReturnTaintRule -> { + if (skipRulePropagation(fact, currentEdge)) continue this += PartiallyResolvedCallAction.CallRule(currentEdge, fact.precondition) } - is CallPreconditionFact.CallToStart -> { + is MethodCallPrecondition.CallToStart -> { this += PartiallyResolvedCallAction.Call2Start(currentEdge, fact) } - is CallPreconditionFact.UnresolvedCallSkip -> { + is MethodCallPrecondition.UnresolvedCallSkip -> { this += PartiallyResolvedCallAction.UnresolvedCallSkip(currentEdge) } } @@ -1381,7 +1449,7 @@ class MethodTraceResolver( private fun resolveCallSummary( statement: CommonInst, callee: MethodEntryPoint, - call2Start: Set, + call2Start: Set, ): List { val resultSummaries = mutableListOf>() for (action in call2Start) { @@ -1573,9 +1641,10 @@ class MethodTraceResolver( private fun MutableList.resolveCallPassSummary( currentEdge: TraceEdge, callee: MethodEntryPoint, - startFact: CallPreconditionFact.CallToStart, + startFact: MethodCallPrecondition.CallToStartResolved, statement: CommonInst ) { + val handler = analysisManager.getMethodCallSummaryPrecondition(apManager, analysisContext, statement) val resolvedCallSummaries = mutableListOf() val methodSummaries = manager.findFactToFactSummaryEdges(callee, startFact.startFactBase) @@ -1588,10 +1657,7 @@ class MethodTraceResolver( if (deltas.isEmpty()) continue - // it is ok to map call arguments via exit2return - val mappedSummaryInitial = methodCallFactMapper.mapMethodExitToReturnFlowFact( - statement, summaryEdge.initialFactAp - ) + val mappedSummaryInitial = handler.callSummaryPrecondition(summaryEdge.initialFactAp, callee) for ((matchedEntryFact, delta) in deltas) { // todo: remove this check? @@ -1626,7 +1692,7 @@ class MethodTraceResolver( if (!mappedSummaryFact.contains(callerFact)) continue val mappedSummaryInitialFacts = summaryEdge.initialFacts.map { - methodCallFactMapper.mapMethodExitToReturnFlowFact(statement, it) + handler.callSummaryPrecondition(it, callee) } mappedSummaryInitialFacts.cartesianProductMapTo { mappedFactGroup -> @@ -1655,7 +1721,7 @@ class MethodTraceResolver( private fun MutableList.resolveCallSourceSummary( currentEdge: TraceEdge.SourceTraceEdge, callee: MethodEntryPoint, - startFact: CallPreconditionFact.CallToStart + startFact: MethodCallPrecondition.CallToStartResolved ) { val relevantSummaryEdges = manager.findZeroToFactSummaryEdges(callee, startFact.startFactBase) val applicableSummaryEdges = relevantSummaryEdges.filter { isApplicableExitToReturnEdge(it) } diff --git a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/VulnerabilityChecker.kt b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/VulnerabilityChecker.kt index 5ad049bad..4aff7100e 100644 --- a/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/VulnerabilityChecker.kt +++ b/core/opentaint-dataflow-core/opentaint-dataflow/src/main/kotlin/org/opentaint/dataflow/ap/ifds/trace/VulnerabilityChecker.kt @@ -131,7 +131,7 @@ class VulnerabilityChecker( for (caller in callers) { val callerFacts = manager.withMethodRunner(caller.callerEp) { intraProcCheck.summaries.flatMapTo(hashSetOf()) { - resolveCalleeFact(caller.callerEp, caller.statement, it) + resolveCalleeFact(caller.callerEp, caller.statement, it, request.ep) } } callerFacts.mapTo(unprocessed) { diff --git a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoAnalysisManager.kt b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoAnalysisManager.kt index a72b68abb..9b588ebea 100644 --- a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoAnalysisManager.kt +++ b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoAnalysisManager.kt @@ -44,6 +44,8 @@ import org.opentaint.ir.go.inst.GoIRInst import org.opentaint.util.analysis.ApplicationGraph import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedQueue +import org.opentaint.dataflow.ap.ifds.trace.MethodCallSummaryPrecondition +import org.opentaint.dataflow.go.trace.GoMethodCallSummaryPrecondition /** * Central factory that wires all Go dataflow analysis components together. @@ -158,6 +160,14 @@ class GoAnalysisManager( ) } + override fun getMethodCallSummaryPrecondition( + apManager: ApManager, + analysisContext: MethodAnalysisContext, + statement: CommonInst + ): MethodCallSummaryPrecondition { + return GoMethodCallSummaryPrecondition(statement as GoIRInst) + } + override fun getMethodSideEffectSummaryHandler( apManager: ApManager, analysisContext: MethodAnalysisContext, diff --git a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoCallRuleBasedSummaryRewriter.kt b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoCallRuleBasedSummaryRewriter.kt index f07eec3f5..56c79c02e 100644 --- a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoCallRuleBasedSummaryRewriter.kt +++ b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoCallRuleBasedSummaryRewriter.kt @@ -57,8 +57,9 @@ class GoCallRuleBasedSummaryRewriter( if (cleanRuleWithCond.condition.isFalse) continue - val positions = cleanRule.actionsAfter.filterIsInstance().mapTo(hashSetOf()) { it.pos } - result += UserRuleDefinedAction(cleanRule, positions, ruleInfo.relevantTaintMarks) + cleanRule.actionsAfter.filterIsInstance().forEach { action -> + result += UserRuleDefinedAction(cleanRule, setOf(action.pos), ruleInfo.relevantTaintMarks + action.mark) + } } result diff --git a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodAnalysisContext.kt b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodAnalysisContext.kt index f6ce7b2e3..2285ba368 100644 --- a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodAnalysisContext.kt +++ b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodAnalysisContext.kt @@ -3,9 +3,7 @@ package org.opentaint.dataflow.go.analysis import org.opentaint.dataflow.ap.ifds.MethodEntryPoint import org.opentaint.dataflow.ap.ifds.TaintAnalysisManager import org.opentaint.dataflow.ap.ifds.analysis.MethodAnalysisContext -import org.opentaint.dataflow.ap.ifds.analysis.MethodCallFactMapper import org.opentaint.dataflow.go.GoClosureTracker.ClosureTracker -import org.opentaint.dataflow.go.GoMethodCallFactMapper import org.opentaint.dataflow.go.analysis.alias.GoLocalAliasAnalysis import org.opentaint.dataflow.go.rules.GoTaintAnalysisContext import org.opentaint.dataflow.util.int2ObjectMap @@ -26,9 +24,6 @@ class GoMethodAnalysisContext( val phase: TaintAnalysisManager.Phase get() = analysisManager.phase - override val methodCallFactMapper: MethodCallFactMapper - get() = GoMethodCallFactMapper - val method: GoIRFunction get() = methodEntryPoint.method as GoIRFunction diff --git a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodCallFlowFunction.kt b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodCallFlowFunction.kt index 06f33f17a..efd37f5de 100644 --- a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodCallFlowFunction.kt +++ b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodCallFlowFunction.kt @@ -3,6 +3,7 @@ package org.opentaint.dataflow.go.analysis import org.opentaint.dataflow.ap.ifds.AccessPathBase import org.opentaint.dataflow.ap.ifds.ExclusionSet import org.opentaint.dataflow.ap.ifds.FactTypeChecker +import org.opentaint.dataflow.ap.ifds.MethodWithContext import org.opentaint.dataflow.ap.ifds.access.ApManager import org.opentaint.dataflow.ap.ifds.access.FinalFactAp import org.opentaint.dataflow.ap.ifds.access.InitialFactAp @@ -52,7 +53,7 @@ class GoMethodCallFlowFunction( } override fun propagateZeroToZero(): Set { - val result = mutableSetOf( + val result = mutableSetOf( CallToReturnZeroFact, CallToStartZeroFact, ) @@ -176,6 +177,7 @@ class GoMethodCallFlowFunction( override fun propagateUnresolvedCallFact( factAp: FinalFactAp, + startFactBase: AccessPathBase, addCallToReturn: (FinalFactReader, FinalFactAp, TraceInfo?) -> Unit, addSideEffectRequirement: (FinalFactReader) -> Unit ) { @@ -234,6 +236,16 @@ class GoMethodCallFlowFunction( } } + override fun propagateSuccessCallFact( + factAp: FinalFactAp, + startFactBase: AccessPathBase, + method: MethodWithContext, + addSideEffectRequirement: (FinalFactReader) -> Unit, + addCallToReturn: (FinalFactReader, FinalFactAp, TraceInfo?) -> Unit, + addCallToStart: (callerFact: FinalFactAp, startFactBase: AccessPathBase, TraceInfo?) -> Unit, + addUnchecked: (MethodCallFlowFunction.CallFact) -> Unit, + ) = addCallToStart(factAp, startFactBase, null) + private fun propagateDefault( factAp: FinalFactAp, addCallToReturn: (FinalFactReader, FinalFactAp, TraceInfo?) -> Unit diff --git a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodCallSummaryHandler.kt b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodCallSummaryHandler.kt index be035855a..6f37f4b92 100644 --- a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodCallSummaryHandler.kt +++ b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/analysis/GoMethodCallSummaryHandler.kt @@ -3,9 +3,11 @@ package org.opentaint.dataflow.go.analysis import org.opentaint.dataflow.ap.ifds.Edge import org.opentaint.dataflow.ap.ifds.ExclusionSet import org.opentaint.dataflow.ap.ifds.FactTypeChecker +import org.opentaint.dataflow.ap.ifds.MethodEntryPoint import org.opentaint.dataflow.ap.ifds.MethodSummaryEdgeApplicationUtils import org.opentaint.dataflow.ap.ifds.access.ApManager import org.opentaint.dataflow.ap.ifds.access.FinalFactAp +import org.opentaint.dataflow.ap.ifds.access.InitialFactAp import org.opentaint.dataflow.ap.ifds.analysis.MethodCallSummaryHandler import org.opentaint.dataflow.ap.ifds.analysis.MethodCallSummaryHandler.SummaryEdge import org.opentaint.dataflow.ap.ifds.analysis.MethodSequentFlowFunction.Sequent @@ -24,7 +26,11 @@ class GoMethodCallSummaryHandler( ) : MethodCallSummaryHandler { override val factTypeChecker: FactTypeChecker = FactTypeChecker.Dummy - override fun mapMethodExitToReturnFlowFact(fact: FinalFactAp): List { + override fun prepareSummaryInitialFact(fact: InitialFactAp, callee: MethodEntryPoint): List { + return GoMethodCallFactMapper.mapMethodExitToReturnFlowFact(statement, fact) + } + + override fun prepareSummaryFinalFact(fact: FinalFactAp, callee: MethodEntryPoint): List { return GoMethodCallFactMapper.mapMethodExitToReturnFlowFact(statement, fact, factTypeChecker) } @@ -41,24 +47,26 @@ class GoMethodCallSummaryHandler( } override fun prepareFactToFactSummary(summaryEdge: Edge.FactToFact): List = - summaryRewriter.rewriteSummaryFact(summaryEdge.factAp).map { (resultFact, refinement) -> - Edge.FactToFact( + summaryRewriter.rewriteSummaryFact(summaryEdge.factAp).flatMap { (resultFact, refinement) -> + val rewrittenEdge = Edge.FactToFact( summaryEdge.methodEntryPoint, refinement.refineFact(summaryEdge.initialFactAp), summaryEdge.statement, refinement.refineFact(resultFact) ) + super.prepareFactToFactSummary(rewrittenEdge) } - override fun prepareNDFactToFactSummary(summaryEdge: Edge.NDFactToFact): List = - summaryRewriter.rewriteSummaryFact(summaryEdge.factAp).map { (resultFact, refinement) -> + override fun prepareNDFactToFactSummary(summaryEdge: Edge.NDFactToFact): List = + summaryRewriter.rewriteSummaryFact(summaryEdge.factAp).flatMap { (resultFact, refinement) -> check(!refinement.hasRefinement) { "Can't refine NDF2F edge" } - Edge.NDFactToFact( + val rewrittenEdge = Edge.NDFactToFact( summaryEdge.methodEntryPoint, summaryEdge.initialFacts, summaryEdge.statement, resultFact, ) + super.prepareNDFactToFactSummary(rewrittenEdge) } override fun handleZeroToZero(summaryFact: FinalFactAp?): Set = diff --git a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/trace/GoMethodCallPrecondition.kt b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/trace/GoMethodCallPrecondition.kt index 0c7f63d37..ea1f68f32 100644 --- a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/trace/GoMethodCallPrecondition.kt +++ b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/trace/GoMethodCallPrecondition.kt @@ -1,6 +1,7 @@ package org.opentaint.dataflow.go.trace import org.opentaint.dataflow.ap.ifds.AccessPathBase +import org.opentaint.dataflow.ap.ifds.MethodWithContext import org.opentaint.dataflow.ap.ifds.TaintMarkAccessor import org.opentaint.dataflow.ap.ifds.access.ApManager import org.opentaint.dataflow.ap.ifds.access.InitialFactAp @@ -8,7 +9,8 @@ import org.opentaint.dataflow.ap.ifds.taint.TaintAnalysisContext.RuleWithConditi import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPrecondition import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPreconditionFact -import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPreconditionFact.CallFailurePreconditionFact +import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallFailurePreconditionFact +import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallSuccessPreconditionFact import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.PreconditionFactsForInitialFact import org.opentaint.dataflow.ap.ifds.trace.TaintRulePrecondition import org.opentaint.dataflow.go.GoCallExpr @@ -77,16 +79,24 @@ class GoMethodCallPrecondition( val result = mutableListOf() if (startFactBase != AccessPathBase.Return) { - result += CallPreconditionFact.UnresolvedCallSkip + result += MethodCallPrecondition.UnresolvedCallSkip } factPassRulePrecondition(fact, startFactBase).mapTo(result) { - CallPreconditionFact.CallToReturnTaintRule(it) + MethodCallPrecondition.CallToReturnTaintRule(it) } return result } + override fun factPreconditionResolutionSuccess( + fact: InitialFactAp, + startFactBase: AccessPathBase, + method: MethodWithContext + ): List = listOf( + MethodCallPrecondition.CallToStartResolved(fact, startFactBase, method) + ) + private fun preconditionForFact(fact: InitialFactAp): List? { if (!factIsRelevantToMethodCall(statement, returnValue, callExpr, fact)) return null @@ -114,10 +124,10 @@ class GoMethodCallPrecondition( startBase: AccessPathBase, ) { factSourceRulePrecondition(fact, startBase).mapTo(this) { - CallPreconditionFact.CallToReturnTaintRule(it) + MethodCallPrecondition.CallToReturnTaintRule(it) } - this += CallPreconditionFact.CallToStart(fact, startBase) + this += MethodCallPrecondition.CallToStart(fact, startBase) } private fun factSourceRulePrecondition( diff --git a/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/trace/GoMethodCallSummaryPrecondition.kt b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/trace/GoMethodCallSummaryPrecondition.kt new file mode 100644 index 000000000..7d46f5e73 --- /dev/null +++ b/core/opentaint-dataflow-core/opentaint-go-dataflow/src/main/kotlin/org/opentaint/dataflow/go/trace/GoMethodCallSummaryPrecondition.kt @@ -0,0 +1,14 @@ +package org.opentaint.dataflow.go.trace + +import org.opentaint.dataflow.ap.ifds.MethodEntryPoint +import org.opentaint.dataflow.ap.ifds.access.InitialFactAp +import org.opentaint.dataflow.ap.ifds.trace.MethodCallSummaryPrecondition +import org.opentaint.dataflow.go.GoMethodCallFactMapper +import org.opentaint.ir.go.inst.GoIRInst + +class GoMethodCallSummaryPrecondition( + private val statement: GoIRInst, +) : MethodCallSummaryPrecondition { + override fun callSummaryPrecondition(fact: InitialFactAp, callee: MethodEntryPoint): List = + GoMethodCallFactMapper.mapMethodExitToReturnFlowFact(statement, fact) +} diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRAnalysisManager.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRAnalysisManager.kt index cf928a62a..2dbb0b260 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRAnalysisManager.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRAnalysisManager.kt @@ -52,6 +52,8 @@ import org.opentaint.jvm.graph.JApplicationGraph import org.opentaint.util.analysis.ApplicationGraph import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedQueue +import org.opentaint.dataflow.ap.ifds.trace.MethodCallSummaryPrecondition +import org.opentaint.dataflow.jvm.ap.ifds.trace.JIRMethodCallSummaryPrecondition class JIRAnalysisManager( cp: JIRClasspath, @@ -236,6 +238,15 @@ class JIRAnalysisManager( } } + override fun getMethodCallSummaryPrecondition( + apManager: ApManager, + analysisContext: MethodAnalysisContext, + statement: CommonInst + ): MethodCallSummaryPrecondition { + jIRDowncast(statement) + return JIRMethodCallSummaryPrecondition(statement) + } + override fun getMethodSideEffectSummaryHandler( apManager: ApManager, analysisContext: MethodAnalysisContext, diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodAnalysisContext.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodAnalysisContext.kt index d9837eac0..e5b9d9d74 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodAnalysisContext.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodAnalysisContext.kt @@ -5,12 +5,10 @@ import org.opentaint.dataflow.ap.ifds.MethodEntryPoint import org.opentaint.dataflow.ap.ifds.TaintAnalysisManager.Phase import org.opentaint.dataflow.ap.ifds.TaintMarkAccessor import org.opentaint.dataflow.ap.ifds.analysis.MethodAnalysisContext -import org.opentaint.dataflow.ap.ifds.analysis.MethodCallFactMapper import org.opentaint.dataflow.jvm.ap.ifds.JIRFactTypeChecker import org.opentaint.dataflow.jvm.ap.ifds.JIRLambdaTracker import org.opentaint.dataflow.jvm.ap.ifds.JIRLocalAliasAnalysis import org.opentaint.dataflow.jvm.ap.ifds.JIRLocalVariableReachability -import org.opentaint.dataflow.jvm.ap.ifds.JIRMethodCallFactMapper import org.opentaint.dataflow.jvm.ap.ifds.taint.JIRTaintAnalysisContext import org.opentaint.dataflow.util.SoftReferenceManager import org.opentaint.dataflow.util.int2ObjectMap @@ -31,9 +29,6 @@ class JIRMethodAnalysisContext( val phase: Phase get() = analysisManager.phase - override val methodCallFactMapper: MethodCallFactMapper - get() = JIRMethodCallFactMapper - val taintMarksAssignedOnMethodEnter = hashSetOf() val lambdaCallResolution = Int2ObjectOpenHashMap() diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt index 5ee1493f3..edf84c819 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt @@ -2,6 +2,7 @@ package org.opentaint.dataflow.jvm.ap.ifds.analysis import org.opentaint.dataflow.ap.ifds.AccessPathBase import org.opentaint.dataflow.ap.ifds.ExclusionSet +import org.opentaint.dataflow.ap.ifds.MethodWithContext import org.opentaint.dataflow.ap.ifds.access.ApManager import org.opentaint.dataflow.ap.ifds.access.FinalFactAp import org.opentaint.dataflow.ap.ifds.access.InitialFactAp @@ -12,6 +13,7 @@ import org.opentaint.dataflow.ap.ifds.analysis.MethodCallFlowFunction.CallToRetu import org.opentaint.dataflow.ap.ifds.analysis.MethodCallFlowFunction.CallToReturnZeroFact import org.opentaint.dataflow.ap.ifds.analysis.MethodCallFlowFunction.CallToStartZeroFact import org.opentaint.dataflow.ap.ifds.analysis.MethodCallFlowFunction.TraceInfo +import org.opentaint.dataflow.ap.ifds.analysis.MethodCallFlowFunction.ZeroCallFact import org.opentaint.dataflow.configuration.jvm.TaintConfigurationItem import org.opentaint.dataflow.configuration.jvm.serialized.UserDefinedRuleInfo import org.opentaint.dataflow.jvm.ap.ifds.JIRCallResolver @@ -53,7 +55,7 @@ class JIRMethodCallFlowFunction( JIRMethodPositionBaseTypeResolver(callExpr.method.method) } - override fun propagateZeroToZero() = buildSet { + override fun propagateZeroToZero(): Set = buildSet { applySinkRules( factReader = null, markAfterAnyFieldResolver = null @@ -252,6 +254,7 @@ class JIRMethodCallFlowFunction( override fun propagateUnresolvedCallFact( factAp: FinalFactAp, + startFactBase: AccessPathBase, addCallToReturn: (FinalFactReader, FinalFactAp, TraceInfo?) -> Unit, addSideEffectRequirement: (FinalFactReader) -> Unit ) { @@ -326,6 +329,16 @@ class JIRMethodCallFlowFunction( } } + override fun propagateSuccessCallFact( + factAp: FinalFactAp, + startFactBase: AccessPathBase, + method: MethodWithContext, + addSideEffectRequirement: (FinalFactReader) -> Unit, + addCallToReturn: (FinalFactReader, FinalFactAp, TraceInfo?) -> Unit, + addCallToStart: (callerFact: FinalFactAp, startFactBase: AccessPathBase, TraceInfo?) -> Unit, + addUnchecked: (MethodCallFlowFunction.CallFact) -> Unit, + ) = addCallToStart(factAp, startFactBase, null) + private fun unresolvedCallDefaultFactPropagation( factAp: FinalFactAp, addCallToReturn: (FinalFactReader, FinalFactAp, TraceInfo?) -> Unit, diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallRuleBasedSummaryRewriter.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallRuleBasedSummaryRewriter.kt index 48db87b26..5c267c2d9 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallRuleBasedSummaryRewriter.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallRuleBasedSummaryRewriter.kt @@ -80,8 +80,9 @@ class JIRMethodCallRuleBasedSummaryRewriter( val simplifiedCondition = conditionRewriter.rewrite(cleanRule.condition) if (simplifiedCondition.isFalse) continue - val positions = cleanRule.actionsAfter.filterIsInstance().mapTo(hashSetOf()) { it.position } - indexRule(cleanRule, positions, ruleInfo.relevantTaintMarks) + cleanRule.actionsAfter.filterIsInstance().forEach { action -> + indexRule(cleanRule, setOf(action.position), ruleInfo.relevantTaintMarks + action.mark.name) + } } result diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallSummaryHandler.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallSummaryHandler.kt index b31fa004a..b01c3d42d 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallSummaryHandler.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallSummaryHandler.kt @@ -3,9 +3,11 @@ package org.opentaint.dataflow.jvm.ap.ifds.analysis import org.opentaint.dataflow.ap.ifds.Edge import org.opentaint.dataflow.ap.ifds.ExclusionSet import org.opentaint.dataflow.ap.ifds.FactTypeChecker +import org.opentaint.dataflow.ap.ifds.MethodEntryPoint import org.opentaint.dataflow.ap.ifds.MethodSummaryEdgeApplicationUtils import org.opentaint.dataflow.ap.ifds.access.ApManager import org.opentaint.dataflow.ap.ifds.access.FinalFactAp +import org.opentaint.dataflow.ap.ifds.access.InitialFactAp import org.opentaint.dataflow.ap.ifds.analysis.MethodCallSummaryHandler import org.opentaint.dataflow.ap.ifds.analysis.MethodCallSummaryHandler.SummaryEdge import org.opentaint.dataflow.ap.ifds.analysis.MethodSequentFlowFunction.Sequent @@ -23,7 +25,10 @@ class JIRMethodCallSummaryHandler( JIRMethodCallRuleBasedSummaryRewriter(statement, analysisContext, apManager) } - override fun mapMethodExitToReturnFlowFact(fact: FinalFactAp): List = + override fun prepareSummaryInitialFact(fact: InitialFactAp, callee: MethodEntryPoint): List = + JIRMethodCallFactMapper.mapMethodExitToReturnFlowFact(statement, fact) + + override fun prepareSummaryFinalFact(fact: FinalFactAp, callee: MethodEntryPoint): List = JIRMethodCallFactMapper.mapMethodExitToReturnFlowFact(statement, fact, factTypeChecker) override fun handleZeroToZero(summaryFact: FinalFactAp?): Set = @@ -69,24 +74,26 @@ class JIRMethodCallSummaryHandler( } override fun prepareFactToFactSummary(summaryEdge: Edge.FactToFact): List = - summaryRewriter.rewriteSummaryFact(summaryEdge.factAp).map { (resultFact, refinement) -> - Edge.FactToFact( + summaryRewriter.rewriteSummaryFact(summaryEdge.factAp).flatMap { (resultFact, refinement) -> + val rewrittenEdge = Edge.FactToFact( summaryEdge.methodEntryPoint, refinement.refineFact(summaryEdge.initialFactAp), summaryEdge.statement, refinement.refineFact(resultFact) ) + super.prepareFactToFactSummary(rewrittenEdge) } - override fun prepareNDFactToFactSummary(summaryEdge: Edge.NDFactToFact): List = - summaryRewriter.rewriteSummaryFact(summaryEdge.factAp).map { (resultFact, refinement) -> + override fun prepareNDFactToFactSummary(summaryEdge: Edge.NDFactToFact): List = + summaryRewriter.rewriteSummaryFact(summaryEdge.factAp).flatMap { (resultFact, refinement) -> check(!refinement.hasRefinement) { "Can't refine NDF2F edge" } - Edge.NDFactToFact( + val rewrittenEdge = Edge.NDFactToFact( summaryEdge.methodEntryPoint, summaryEdge.initialFacts, summaryEdge.statement, resultFact, ) + super.prepareNDFactToFactSummary(rewrittenEdge) } private fun applyCallAliases(fact: FinalFactAp, body: (FinalFactAp) -> Unit) { diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallPrecondition.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallPrecondition.kt index c9b0f53a0..c8d1921c6 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallPrecondition.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallPrecondition.kt @@ -1,15 +1,16 @@ package org.opentaint.dataflow.jvm.ap.ifds.trace import org.opentaint.dataflow.ap.ifds.AccessPathBase +import org.opentaint.dataflow.ap.ifds.MethodWithContext import org.opentaint.dataflow.ap.ifds.TaintMarkAccessor import org.opentaint.dataflow.ap.ifds.access.ApManager import org.opentaint.dataflow.ap.ifds.access.InitialFactAp -import org.opentaint.dataflow.ap.ifds.analysis.MethodCallFactMapper import org.opentaint.dataflow.ap.ifds.taint.TaintAnalysisContext.RuleWithCondition import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition +import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallFailurePreconditionFact import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPrecondition import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPreconditionFact -import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallPreconditionFact.CallFailurePreconditionFact +import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.CallSuccessPreconditionFact import org.opentaint.dataflow.ap.ifds.trace.MethodCallPrecondition.PreconditionFactsForInitialFact import org.opentaint.dataflow.ap.ifds.trace.TaintRulePrecondition import org.opentaint.dataflow.configuration.jvm.TaintMethodSource @@ -40,8 +41,6 @@ class JIRMethodCallPrecondition( private val callExpr: JIRCallExpr, private val statement: JIRInst, ) : MethodCallPrecondition.Default { - private val methodCallFactMapper: MethodCallFactMapper get() = analysisContext.methodCallFactMapper - private val taintCtx get() = analysisContext.taint override fun factPrecondition(fact: InitialFactAp): List { @@ -64,7 +63,7 @@ class JIRMethodCallPrecondition( val preconditions = mutableListOf() if (startFactBase != AccessPathBase.Return) { - preconditions += CallPreconditionFact.UnresolvedCallSkip + preconditions += MethodCallPrecondition.UnresolvedCallSkip } preconditions += rulePreconditionForFactResolutionFailure(fact, startFactBase) @@ -72,6 +71,14 @@ class JIRMethodCallPrecondition( return preconditions } + override fun factPreconditionResolutionSuccess( + fact: InitialFactAp, + startFactBase: AccessPathBase, + method: MethodWithContext + ): List = listOf( + MethodCallPrecondition.CallToStartResolved(fact, startFactBase, method) + ) + private fun preconditionForFact(fact: InitialFactAp): List? { if (!factIsRelevantToMethodCall(statement, returnValue, callExpr, fact)) { return null @@ -103,9 +110,9 @@ class JIRMethodCallPrecondition( val rulePreconditions = mutableListOf() rulePreconditions.factSourceRulePrecondition(fact, startBase) - rulePreconditions.mapTo(this) { CallPreconditionFact.CallToReturnTaintRule(it) } + rulePreconditions.mapTo(this) { MethodCallPrecondition.CallToReturnTaintRule(it) } - this += CallPreconditionFact.CallToStart(fact, startBase) + this += MethodCallPrecondition.CallToStart(fact, startBase) } private fun rulePreconditionForFactResolutionFailure( @@ -115,7 +122,7 @@ class JIRMethodCallPrecondition( val rulePreconditions = mutableListOf() rulePreconditions.factPassRulePrecondition(fact, startBase) - return rulePreconditions.map { CallPreconditionFact.CallToReturnTaintRule(it) } + return rulePreconditions.map { MethodCallPrecondition.CallToReturnTaintRule(it) } } private fun MutableList.factSourceRulePrecondition( @@ -179,5 +186,5 @@ class JIRMethodCallPrecondition( statement.location.method.instList.toList() override fun mapExit2Return(fact: InitialFactAp): List = - methodCallFactMapper.mapMethodExitToReturnFlowFact(statement, fact) + JIRMethodCallFactMapper.mapMethodExitToReturnFlowFact(statement, fact) } diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallSummaryPrecondition.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallSummaryPrecondition.kt new file mode 100644 index 000000000..19c2efa61 --- /dev/null +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallSummaryPrecondition.kt @@ -0,0 +1,14 @@ +package org.opentaint.dataflow.jvm.ap.ifds.trace + +import org.opentaint.dataflow.ap.ifds.MethodEntryPoint +import org.opentaint.dataflow.ap.ifds.access.InitialFactAp +import org.opentaint.dataflow.ap.ifds.trace.MethodCallSummaryPrecondition +import org.opentaint.dataflow.jvm.ap.ifds.JIRMethodCallFactMapper +import org.opentaint.ir.api.jvm.cfg.JIRInst + +class JIRMethodCallSummaryPrecondition( + private val statement: JIRInst, +) : MethodCallSummaryPrecondition { + override fun callSummaryPrecondition(fact: InitialFactAp, callee: MethodEntryPoint): List = + JIRMethodCallFactMapper.mapMethodExitToReturnFlowFact(statement, fact) +} diff --git a/core/opentaint-java-querylang/samples/src/main/java/example/RuleWithEllipsisMethodInvocation.java b/core/opentaint-java-querylang/samples/src/main/java/example/RuleWithEllipsisMethodInvocation.java index bafa6e8ef..378f5f593 100644 --- a/core/opentaint-java-querylang/samples/src/main/java/example/RuleWithEllipsisMethodInvocation.java +++ b/core/opentaint-java-querylang/samples/src/main/java/example/RuleWithEllipsisMethodInvocation.java @@ -6,7 +6,7 @@ @RuleSet("example/RuleWithEllipsisMethodInvocation.yaml") public abstract class RuleWithEllipsisMethodInvocation implements RuleSample { Inner src() { - return new Inner(new Object()); + return new Inner(new Inner2()); } void sink(String data) {} @@ -15,7 +15,7 @@ final static class PositiveOneCall extends RuleWithEllipsisMethodInvocation { @Override public void entrypoint() { Inner data = src(); - String str = data.getObjGood().toString(); + String str = data.getInner().toString(); sink(str); } } @@ -33,19 +33,27 @@ final static class NegativeTwoCalls extends RuleWithEllipsisMethodInvocation { @Override public void entrypoint() { Inner data = src(); - String str = data.getObjGood().getClass().toString(); + String str = data.getInner().getObjGood().toString(); sink(str); } } + private static final class Inner2 { + final private Object obj = new Object(); + + public Object getObjGood() { + return obj; + } + } + static final private class Inner { - final private Object obj; + final private Inner2 obj; - public Inner(Object obj) { + public Inner(Inner2 obj) { this.obj = obj; } - public Object getObjGood() { + public Inner2 getInner() { return obj; } } diff --git a/core/opentaint-java-querylang/src/main/kotlin/org/opentaint/semgrep/pattern/conversion/taint/TaintRuleGenerationCtx.kt b/core/opentaint-java-querylang/src/main/kotlin/org/opentaint/semgrep/pattern/conversion/taint/TaintRuleGenerationCtx.kt index c13ae60c7..ec70f7fc5 100644 --- a/core/opentaint-java-querylang/src/main/kotlin/org/opentaint/semgrep/pattern/conversion/taint/TaintRuleGenerationCtx.kt +++ b/core/opentaint-java-querylang/src/main/kotlin/org/opentaint/semgrep/pattern/conversion/taint/TaintRuleGenerationCtx.kt @@ -152,8 +152,7 @@ data class TaintRuleGenerationCtx( fun edgeRuleInfo(edge: TaintRuleEdge): UserRuleFromSemgrepInfo { val relevantTaintMarks = hashSetOf() relevantTaintMarks += usedTaintMarks(edge.stateFrom) - relevantTaintMarks += usedTaintMarks(edge.stateTo) - if (edge.checkGlobalState || edge.stateTo in globalStateAssignStates) { + if (edge.checkGlobalState) { relevantTaintMarks += globalStateMarkName(edge.stateTo) }