Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ seqraOrg=seqra
seqraBuildVersion=2025.10.01.6b66511

seqraIrVersion=2026.02.01.c54b6cc
seqraConfigVersion=2026.02.01.02e636c
seqraConfigVersion=2026.03.01.a18a707
seqraUtilVersion=2026.02.01.44bb600
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ class MethodEdgesInitialToFinalTreeApSet(

val currentAccess = edges[edgeSetIdx]!!
val mergedAccess = currentAccess.mergeAdd(accessWithExclusion.access)
if (mergedAccess === currentAccess) return null
if (mergedAccess === currentAccess) {
if (mergedExclusion === currentExclusion) return null

return AccessWithExclusion(mergedAccess, mergedExclusion)
}

edges[edgeSetIdx] = mergedAccess
return AccessWithExclusion(mergedAccess, mergedExclusion)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ class CompactGraphTopSort(val graph: CompactGraph) {
fun graphTopOrderNodeComparator(startNode: Int): IntComparator {
val topOrderPriority = graphTopOrderNodePriority(startNode)
return IntComparator { k1: Int, k2: Int ->
val k1Priority = topOrderPriority.get(k1)
check(k1Priority != NO_NODE) {
"Node: $k1 missed in top order"
var k1Priority = topOrderPriority.get(k1)
if (k1Priority == NO_NODE) {
// todo: consider better approach, maybe better analyze exceptional flows
k1Priority = graph.size + k1
}

val k2Priority = topOrderPriority.get(k2)
check(k2Priority != NO_NODE) {
"Node: $k2 missed in top order"
var k2Priority = topOrderPriority.get(k2)
if (k2Priority == NO_NODE) {
k2Priority = graph.size + k2
}

k1Priority.compareTo(k2Priority)
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
package org.seqra.dataflow.jvm.ap.ifds

import org.seqra.dataflow.configuration.jvm.Argument
import org.seqra.dataflow.configuration.jvm.ClassStatic
import org.seqra.dataflow.configuration.jvm.Position
import org.seqra.dataflow.configuration.jvm.PositionResolver
import org.seqra.dataflow.configuration.jvm.PositionWithAccess
import org.seqra.dataflow.configuration.jvm.Result
import org.seqra.dataflow.configuration.jvm.This
import org.seqra.dataflow.jvm.util.isVararg
import org.seqra.dataflow.jvm.util.thisInstance
import org.seqra.dataflow.jvm.util.varargParamIdx
import org.seqra.ir.api.jvm.JIRClasspath
import org.seqra.ir.api.jvm.JIRMethod
import org.seqra.ir.api.jvm.JIRParameter
Expand All @@ -10,43 +20,47 @@ import org.seqra.ir.api.jvm.cfg.JIRImmediate
import org.seqra.ir.api.jvm.cfg.JIRInstanceCallExpr
import org.seqra.ir.api.jvm.cfg.JIRValue
import org.seqra.ir.api.jvm.ext.toType
import org.seqra.dataflow.configuration.jvm.Argument
import org.seqra.dataflow.configuration.jvm.ClassStatic
import org.seqra.dataflow.configuration.jvm.Position
import org.seqra.dataflow.configuration.jvm.PositionResolver
import org.seqra.dataflow.configuration.jvm.PositionWithAccess
import org.seqra.dataflow.configuration.jvm.Result
import org.seqra.dataflow.configuration.jvm.This
import org.seqra.dataflow.jvm.util.thisInstance
import org.seqra.util.Maybe
import org.seqra.util.fmap
import org.seqra.util.toMaybe

sealed interface CallPositionValue {
data object None : CallPositionValue
data class Value(val value: JIRValue) : CallPositionValue
data class VarArgValue(val value: JIRValue) : CallPositionValue
}

class CallPositionToJIRValueResolver(
private val callExpr: JIRCallExpr,
private val returnValue: JIRImmediate?
) : PositionResolver<Maybe<JIRValue>> {
override fun resolve(position: Position): Maybe<JIRValue> = when (position) {
is Argument -> callExpr.args.getOrNull(position.index).toMaybe()
This -> (callExpr as? JIRInstanceCallExpr)?.instance.toMaybe()
Result -> returnValue.toMaybe()
is PositionWithAccess -> Maybe.none() // todo?
is ClassStatic -> Maybe.none()
) : PositionResolver<CallPositionValue> {
override fun resolve(position: Position): CallPositionValue = when (position) {
is Argument -> callExpr.args.getOrNull(position.index)
.toCallArgValue(callExpr.method.method, position.index)

is This -> (callExpr as? JIRInstanceCallExpr)?.instance.toCallValue()
is Result -> returnValue.toCallValue()

is PositionWithAccess, // todo?
is ClassStatic -> CallPositionValue.None
}
}

class CalleePositionToJIRValueResolver(
private val method: JIRMethod
) : PositionResolver<Maybe<JIRValue>> {
) : PositionResolver<CallPositionValue> {
private val cp = method.enclosingClass.classpath

override fun resolve(position: Position): Maybe<JIRValue> = when (position) {
is Argument -> cp.getArgument(method.parameters[position.index]).toMaybe()
This -> method.thisInstance.toMaybe()
is PositionWithAccess -> resolve(position.base).fmap { TODO() }
override fun resolve(position: Position): CallPositionValue = when (position) {
is Argument -> method.parameters.getOrNull(position.index)
?.let { cp.getArgument(it) }
.toCallArgValue(method, position.index)

is This -> method.thisInstance.toCallValue()

// todo
is PositionWithAccess -> CallPositionValue.None

// Inapplicable callee positions
Result -> Maybe.none()
is ClassStatic -> Maybe.none()
is Result,
is ClassStatic -> CallPositionValue.None
}

private fun JIRClasspath.getArgument(param: JIRParameter): JIRArgument? {
Expand All @@ -66,3 +80,14 @@ class JIRMethodPositionBaseTypeResolver(private val method: JIRMethod) : Positio
is ClassStatic -> null
}
}

private fun JIRValue?.toCallArgValue(method: JIRMethod, argumentIdx: Int): CallPositionValue {
val value = this ?: return CallPositionValue.None
if (method.isVararg() && argumentIdx == method.varargParamIdx()) {
return CallPositionValue.VarArgValue(value)
}
return CallPositionValue.Value(value)
}

private fun JIRValue?.toCallValue(): CallPositionValue =
this?.let { CallPositionValue.Value(it) } ?: CallPositionValue.None
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,19 @@ class JIRLocalAliasAnalysis(
instIdx: Int, base: AccessPathBase.LocalVar
): List<AliasInfo>? =
alias[instIdx].getOrDefault(base.idx, null)?.filter {
it.accessors.isNotEmpty() || it.base != base
it !is AliasApInfo || it.accessors.isNotEmpty() || it.base != base
}

fun findAlias(base: AccessPathBase.LocalVar, statement: CommonInst): List<AliasInfo>? {
val idx = languageManager.getInstIndex(statement)
return getLocalVarAliases(aliasInfo.aliasBeforeStatement, idx, base)
}

fun getAllAliasAtStatement(statement: CommonInst): Int2ObjectOpenHashMap<List<AliasInfo>> {
val idx = languageManager.getInstIndex(statement)
return aliasInfo.aliasBeforeStatement[idx]
}

fun findAliasAfterStatement(base: AccessPathBase.LocalVar, statement: CommonInst): List<AliasInfo>? {
val idx = languageManager.getInstIndex(statement)
return getLocalVarAliases(aliasInfo.aliasAfterStatement, idx, base)
Expand All @@ -50,14 +55,11 @@ class JIRLocalAliasAnalysis(
}

sealed interface AliasAccessor {
data class Field(
val className: String,
val fieldName: String,
val fieldType: String
) : AliasAccessor

data class Field(val className: String, val fieldName: String, val fieldType: String) : AliasAccessor
data object Array : AliasAccessor
}

data class AliasInfo(val base: AccessPathBase, val accessors: List<AliasAccessor> = emptyList())
sealed interface AliasInfo
data class AliasApInfo(val base: AccessPathBase, val accessors: List<AliasAccessor>): AliasInfo
data class AliasAllocInfo(val allocInst: Int): AliasInfo
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@ import org.seqra.dataflow.jvm.ap.ifds.analysis.JIRMethodAnalysisContext
import org.seqra.dataflow.jvm.ap.ifds.taint.ContainsMarkOnAnyField
import org.seqra.dataflow.jvm.ap.ifds.taint.JIRBasicAtomEvaluator
import org.seqra.ir.api.common.cfg.CommonInst
import org.seqra.ir.api.jvm.cfg.JIRValue
import org.seqra.util.Maybe

class JIRMarkAwareConditionRewriter(
positionResolver: PositionResolver<Maybe<JIRValue>>,
positionResolver: PositionResolver<CallPositionValue>,
analysisContext: JIRMethodAnalysisContext,
statement: CommonInst,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.seqra.dataflow.jvm.ap.ifds.alias

import it.unimi.dsi.fastutil.ints.Int2ObjectMap
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import org.seqra.dataflow.jvm.ap.ifds.JIRLocalAliasAnalysis.AliasAccessor
import org.seqra.dataflow.jvm.ap.ifds.alias.JIRIntraProcAliasAnalysis.JIRInstGraph
import org.seqra.dataflow.jvm.ap.ifds.alias.RefValue.Local
import org.seqra.ir.api.jvm.JIRField
Expand Down Expand Up @@ -37,7 +38,7 @@ class DSUAliasAnalysis(
)

private object RootInstEvalContext : InstEvalContext {
override fun createThis(): RefValue = RefValue.This
override fun createThis(isOuter: Boolean): RefValue = RefValue.This(isOuter)
override fun createArg(idx: Int): RefValue = RefValue.Arg(idx)
override fun createLocal(idx: Int): Local = Local(idx, level = 0, ctx = 0)
}
Expand Down Expand Up @@ -121,7 +122,7 @@ class DSUAliasAnalysis(

data class FieldAlias(
override val instance: AAInfo,
val field: JIRField,
val field: AliasAccessor.Field,
override val depth: Int,
override val isImmutable: Boolean,
) : HeapAlias
Expand Down Expand Up @@ -314,10 +315,15 @@ class DSUAliasAnalysis(
}

private fun createFieldAliasWrtLimit(instance: AAInfo, field: JIRField): FieldAlias? {
val f = AliasAccessor.Field(field.enclosingClass.name, field.name, field.type.typeName)
return createFieldAliasWrtLimit(instance, f, field.isFinal)
}

private fun createFieldAliasWrtLimit(instance: AAInfo, field: AliasAccessor.Field, fieldIsImmutable: Boolean): FieldAlias? {
val immutability = when (instance) {
is HeapAlias -> instance.isImmutable
else -> true
} && field.isFinal
} && fieldIsImmutable
return createHeapAliasWrtLimit(instance) { depth -> FieldAlias(instance, field, depth, immutability) }
}

Expand Down Expand Up @@ -411,9 +417,9 @@ class DSUAliasAnalysis(

private fun RefValue.isOuter(): Boolean = when (this) {
is Local -> false
is RefValue.This -> isOuter
is RefValue.Arg,
is RefValue.Static,
is RefValue.This -> true
is RefValue.Static -> true
}

private fun GraphAnalysisState.mapCallFinalStates(
Expand Down Expand Up @@ -498,7 +504,7 @@ class DSUAliasAnalysis(

when (this) {
is ArrayAlias -> createArrayAliasWrtLimit(instanceAlternative)
is FieldAlias -> createFieldAliasWrtLimit(instanceAlternative, field)
is FieldAlias -> createFieldAliasWrtLimit(instanceAlternative, field, isImmutable)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ private class NestedCallInstEvalCtx(val call: Stmt.Call, val level: Int) : InstE
override fun createArg(idx: Int): Value = call.args.getOrNull(idx)
?: error("Incorrect argument idx: $idx")

override fun createThis(): Value = call.instance
override fun createThis(isOuter: Boolean): Value = call.instance
?: error("Non instance call")

override fun createLocal(idx: Int): Local = Local(idx, level = level, ctx = call.originalIdx)
Expand Down
Loading
Loading