diff --git a/gradle.properties b/gradle.properties index 5f7f049..3a28aaf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,6 @@ seqraOrg=seqra seqraBuildVersion=2025.10.01.6b66511 -seqraIrVersion=2026.01.15.1f3bbc2 -seqraConfigVersion=2026.01.15.7ea9c38 -seqraUtilVersion=2026.01.15.c5a77a9 +seqraIrVersion=2026.01.21.17b5bbb +seqraConfigVersion=2026.01.21.57ada3f +seqraUtilVersion=2026.01.21.d61d52a diff --git a/seqra-dataflow/src/main/kotlin/org/seqra/dataflow/ap/ifds/trace/MethodTraceResolver.kt b/seqra-dataflow/src/main/kotlin/org/seqra/dataflow/ap/ifds/trace/MethodTraceResolver.kt index 6f8d03b..858cd46 100644 --- a/seqra-dataflow/src/main/kotlin/org/seqra/dataflow/ap/ifds/trace/MethodTraceResolver.kt +++ b/seqra-dataflow/src/main/kotlin/org/seqra/dataflow/ap/ifds/trace/MethodTraceResolver.kt @@ -1245,6 +1245,9 @@ class MethodTraceResolver( } val currentInitialFacts = object2IntMap() + + // note: we always have zero fact + val zeroFactIdx = addEdgeInitialFact(currentInitialFacts, fact = null) currentEdges.forEach { addEdgeInitialFacts(currentInitialFacts, it) } val currentInitialFactsSet = BitSet(currentInitialFacts.size) @@ -1257,6 +1260,8 @@ class MethodTraceResolver( ?: return@cartesianProductMapTo } + // note: add zero fact since currentFactSet always contains it + matchedInitials.set(zeroFactIdx) if (matchedInitials != currentInitialFactsSet) { return@cartesianProductMapTo } @@ -1281,8 +1286,8 @@ class MethodTraceResolver( private fun addEdgeInitialFact( initialFactIndex: ConcurrentReadSafeObject2IntMap, fact: InitialFactAp?, - ) { - initialFactIndex.getOrCreateIndex(fact?.replaceExclusions(ExclusionSet.Universe)) { return } + ): Int { + return initialFactIndex.getOrCreateIndex(fact?.replaceExclusions(ExclusionSet.Universe)) { return it } } private fun addEdgeInitialFactsIfRegistered( diff --git a/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/JIRFactTypeChecker.kt b/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/JIRFactTypeChecker.kt index bbc1c54..2fc00dc 100644 --- a/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/JIRFactTypeChecker.kt +++ b/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/JIRFactTypeChecker.kt @@ -276,20 +276,30 @@ class JIRFactTypeChecker(private val cp: JIRClasspath) : FactTypeChecker { // todo: fix config private val badElementAccessor = FieldAccessor("java.lang.Object", "Element", "java.lang.Object") - private val elementAccessors = listOf( - FieldAccessor("java.lang.Iterable", "Element", "java.lang.Object"), - FieldAccessor("java.util.Iterator", "Element", "java.lang.Object"), + + private val elementBases = listOf( + "java.lang.Iterable", + "java.util.Iterator", + "java.util.Optional", ) - private val badMapKeyAccessor = FieldAccessor("java.lang.Object", "MapKey", "java.lang.Object") - private val mapKeyAccessors = listOf( - FieldAccessor("java.util.Map", "MapKey", "java.lang.Object"), - FieldAccessor("java.util.Map\$Entry", "MapKey", "java.lang.Object"), + private val elementAccessors = elementBases.map { + FieldAccessor(it, "Element", "java.lang.Object") + } + + private val mapBases = listOf( + "java.util.Map", + "java.util.Map\$Entry", + "org.springframework.http.ResponseEntity" ) + private val badMapKeyAccessor = FieldAccessor("java.lang.Object", "MapKey", "java.lang.Object") + private val mapKeyAccessors = mapBases.map { + FieldAccessor(it, "MapKey", "java.lang.Object") + } + private val badMapValueAccessor = FieldAccessor("java.lang.Object", "MapValue", "java.lang.Object") - private val mapValueAccessors = listOf( - FieldAccessor("java.util.Map", "MapValue", "java.lang.Object"), - FieldAccessor("java.util.Map\$Entry", "MapValue", "java.lang.Object"), - ) + private val mapValueAccessors = mapBases.map { + FieldAccessor(it, "MapValue", "java.lang.Object") + } } diff --git a/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/JIRMethodCallFactMapper.kt b/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/JIRMethodCallFactMapper.kt index 0b3eb1f..e8d9207 100644 --- a/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/JIRMethodCallFactMapper.kt +++ b/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/JIRMethodCallFactMapper.kt @@ -143,6 +143,7 @@ object JIRMethodCallFactMapper : MethodCallFactMapper { val callExpr = callStatement.callExpr ?: error("Non call statement") + val returnValue: JIRImmediate? = (callStatement as? JIRAssignInst)?.lhv?.let { it as? JIRImmediate ?: error("Non simple return value: $callStatement") } @@ -154,7 +155,7 @@ object JIRMethodCallFactMapper : MethodCallFactMapper { } is AccessPathBase.Argument -> { - val argExpr = callExpr.args.getOrNull(base.idx) ?: error("Call $callExpr has no arg $factAp") + val argExpr = callExpr.args.getOrNull(base.idx) ?: return null val newBase = MethodFlowFunctionUtils.accessPathBase(argExpr) ?: return null if (newBase is AccessPathBase.Constant) return null diff --git a/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/analysis/JIRMethodCallRuleBasedSummaryRewriter.kt b/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/analysis/JIRMethodCallRuleBasedSummaryRewriter.kt index a70557e..5c44701 100644 --- a/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/analysis/JIRMethodCallRuleBasedSummaryRewriter.kt +++ b/seqra-jvm-dataflow/src/main/kotlin/org/seqra/dataflow/jvm/ap/ifds/analysis/JIRMethodCallRuleBasedSummaryRewriter.kt @@ -41,7 +41,7 @@ class JIRMethodCallRuleBasedSummaryRewriter( private data class UserRuleDefinedAction( val rule: TaintConfigurationItem, - val positions: List, + val positions: Set, val controlledMarks: Set ) @@ -55,7 +55,7 @@ class JIRMethodCallRuleBasedSummaryRewriter( val simplifiedCondition = conditionRewriter.rewrite(sourceRule.condition) if (simplifiedCondition.isFalse) continue - val positions = sourceRule.actionsAfter.map { it.position } + val positions = sourceRule.actionsAfter.mapTo(hashSetOf()) { it.position } result += UserRuleDefinedAction(sourceRule, positions, ruleInfo.relevantTaintMarks) } @@ -65,7 +65,7 @@ class JIRMethodCallRuleBasedSummaryRewriter( val simplifiedCondition = conditionRewriter.rewrite(cleanRule.condition) if (simplifiedCondition.isFalse) continue - val positions = cleanRule.actionsAfter.filterIsInstance().map { it.position } + val positions = cleanRule.actionsAfter.filterIsInstance().mapTo(hashSetOf()) { it.position } result += UserRuleDefinedAction(cleanRule, positions, ruleInfo.relevantTaintMarks) }