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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ inline fun IntCollection.forEachInt(block: (Int) -> Unit) {
}
}

fun IntCollection.firstInt(): Int = intIterator().nextInt()

inline fun IntList.reversedForEachInt(block: (Int) -> Unit) {
val iter = listIterator(size)
while (iter.hasPrevious()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package sample.alias;

import java.nio.ByteBuffer;

public final class FlakyAliasSample {

interface Pooled<T> {
T getResource();
}

private Pooled<ByteBuffer> buffer;

static void sinkOneValue(Object v) { }

public int write(java.nio.ByteBuffer src) {
java.nio.ByteBuffer[] arr = new java.nio.ByteBuffer[]{src};
flushBufferWithUserData(arr);
sinkOneValue(arr);
return 0;
}

long flushBufferWithUserData(final ByteBuffer[] byteBuffers) {
final ByteBuffer byteBuffer = buffer.getResource();

ByteBuffer[] writeBufs = new ByteBuffer[100 + 1];
writeBufs[0] = byteBuffer;

for (int i = 0; i < 100; i++) {
writeBufs[i] = byteBuffers[i];
byteBuffers[i].remaining();
}

sinkOneValue(writeBufs);
return 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package sample.alias;

public final class HeaderValuesHangSample {

public static void sinkOneValue(Object v) {}

String[] value;

public void addAllEntry() {
ElementBox box = new ElementBox();
for (int i = 0; i < 1; i++) {
String headerValue = box.nextItem;
outOfAnalysisScopeFn1(this.value);
this.value[0] = headerValue;
}

Object out = this;
sinkOneValue(out);
}

public static class ElementBox {
public String nextItem;
}

private static void outOfAnalysisScopeFn0(Object o) {
}

private static void outOfAnalysisScopeFn1(Object o) {
outOfAnalysisScopeFn0(o);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,33 @@ import org.opentaint.dataflow.jvm.ap.ifds.JIRLocalAliasAnalysis.AliasAccessor
import org.opentaint.dataflow.jvm.ap.ifds.JIRLocalVariableReachability
import org.opentaint.dataflow.jvm.ap.ifds.alias.JIRIntraProcAliasAnalysis.JIRInstGraph
import org.opentaint.dataflow.jvm.ap.ifds.alias.RefValue.Local
import org.opentaint.dataflow.util.firstInt
import org.opentaint.dataflow.util.forEachInt
import org.opentaint.dataflow.util.forEachIntEntry
import org.opentaint.dataflow.util.mapIntTo
import org.opentaint.ir.api.jvm.JIRField
import org.opentaint.ir.api.jvm.JIRMethod
import org.opentaint.ir.api.jvm.cfg.JIRInst
import org.opentaint.ir.api.jvm.cfg.JIRReturnInst
import java.util.BitSet

class DSUAliasAnalysis(
val methodCallResolver: CallResolver,
val rootMethodReachabilityInfo: JIRLocalVariableReachability,
val rootMethodReachabilityInfo: JIRLocalVariableReachability?,
val cancellation: AnalysisCancellation
) {
private val aliasManager = AAInfoManager()
private val dsuMergeStrategy = DsuMergeStrategy(aliasManager)
val aliasManager = AAInfoManager()
val dsuMergeStrategy = DsuMergeStrategy(aliasManager)

private val nestedReachabilityInfo = hashMapOf<JIRMethod, JIRLocalVariableReachability>()

private fun methodReachabilityInfo(method: JIRMethod): JIRLocalVariableReachability {
if (method == rootMethodReachabilityInfo.method) return rootMethodReachabilityInfo
private fun methodReachabilityInfo(method: JIRMethod): JIRLocalVariableReachability? {
val rootReachabilityInfo = rootMethodReachabilityInfo ?: return null
if (method == rootReachabilityInfo.method) return rootMethodReachabilityInfo
return nestedReachabilityInfo.getOrPut(method) {
JIRLocalVariableReachability(
method,
rootMethodReachabilityInfo.graph,
rootMethodReachabilityInfo.languageManager
rootReachabilityInfo.graph,
rootReachabilityInfo.languageManager
)
}
}
Expand Down Expand Up @@ -352,10 +353,12 @@ class DSUAliasAnalysis(
}

private fun State.removeUnreachableLocals(
reachabilityInfo: JIRLocalVariableReachability,
reachabilityInfo: JIRLocalVariableReachability?,
instIdx: Int,
call: CallTreeNode
): State {
if (reachabilityInfo == null) return this

val unreachableLocals = IntOpenHashSet()
allElements().forEachInt {
val element = manager.getElementUncheck(it)
Expand Down Expand Up @@ -443,61 +446,61 @@ class DSUAliasAnalysis(
return State.merge(aliasManager, dsuMergeStrategy, statesAfterCall)
}

private fun State.invalidateOuterHeapAliases(startInvalidAliases: IntOpenHashSet): State {
val invalidAliases = collectTransitiveInvalidAliases(startInvalidAliases)
fun State.invalidateOuterHeapAliases(startInvalidAliases: IntOpenHashSet): State {
val allAliasSets = allAliasSets()

val invalidHeapAliases = IntOpenHashSet()
invalidAliases.forEach {
val element = aliasManager.getElementUncheck(it)
if (element !is HeapAlias || isHeapImmutable(element, IntOpenHashSet())) return@forEach
val invalidAliasRepr = IntOpenHashSet()
val heapAliasToRemove = IntOpenHashSet()

invalidHeapAliases.add(it)
startInvalidAliases.forEachInt { id ->
invalidAliasRepr.add(aliasGroupRepr(id))
}

return removeUnsafe(invalidHeapAliases)
}
allAliasSets.forEach { group ->
if (groupContainsSimpleOuterAlias(group)) {
invalidAliasRepr.add(aliasGroupRepr(group.firstInt()))
}
}

private fun State.collectTransitiveInvalidAliases(startInvalidAliases: IntOpenHashSet): IntOpenHashSet {
val currentAliasGroups = allAliasSets().toList()
do {
val sizeBefore = heapAliasToRemove.size + invalidAliasRepr.size

val invalidAliases = IntOpenHashSet()
invalidAliases.addAll(startInvalidAliases)
for (group in allAliasSets) {
group.forEachInt { id ->
if (id in heapAliasToRemove) return@forEachInt

val invalidGroups = BitSet()
val info = aliasManager.getElementUncheck(id)
if (info !is HeapAlias) return@forEachInt

do {
val before = invalidAliases.size
if (aliasGroupRepr(info.instance) !in invalidAliasRepr) return@forEachInt

for ((i, aliasSet) in currentAliasGroups.withIndex()) {
if (invalidGroups.get(i)) continue
if (isHeapImmutable(info, IntOpenHashSet())) return@forEachInt

if (aliasGroupContainsInvalidOrOuter(aliasSet, invalidAliases)) {
invalidGroups.set(i)
invalidAliases.addAll(aliasSet)
heapAliasToRemove.add(id)
invalidAliasRepr.add(aliasGroupRepr(id))
}
}
} while (heapAliasToRemove.size + invalidAliasRepr.size > sizeBefore)

} while (before < invalidAliases.size)

return invalidAliases
return removeUnsafe(heapAliasToRemove)
}

private fun State.aliasGroupContainsInvalidOrOuter(group: IntCollection, invalid: IntOpenHashSet): Boolean {
private fun groupContainsSimpleOuterAlias(group: IntCollection): Boolean {
group.forEachInt { aInfoIndex ->
when (val aInfo = aliasManager.getElementUncheck(aInfoIndex)) {
is Unknown -> return true
is CallReturn -> return true
is HeapAlias -> if (aliasGroupRepr(aInfo.instance) in invalid) return true
is LocalAlias.Alloc -> return@forEachInt
is LocalAlias.SimpleLoc -> {
if (aInfo.loc.isOuter()) return true
if (aInfoIndex in invalid) return true
}
}
if (aInfoIndex.aliasInfoIsSimpleOuter()) return true
}
return false
}

private fun Int.aliasInfoIsSimpleOuter(): Boolean =
when (val aInfo = aliasManager.getElementUncheck(this)) {
is Unknown -> true
is CallReturn -> true
is LocalAlias.SimpleLoc -> aInfo.loc.isOuter()
is LocalAlias.Alloc -> false
is HeapAlias -> false
}

private fun evalSimple(stmt: Stmt.NoCall, callFrame: CallTreeNode, state: State): State = when (stmt) {
is Stmt.Assign -> evalAssign(stmt, callFrame, state)

Expand Down Expand Up @@ -595,6 +598,7 @@ class DSUAliasAnalysis(
) = evalHeapLoad(load.instance, state) { instance -> createFieldAlias(instance, load.field) }

private fun evalHeapStore(
isFieldStore: Boolean,
instance: RefValue,
value: ExprOrValue,
state: State,
Expand All @@ -606,7 +610,7 @@ class DSUAliasAnalysis(
val heapAlias = heapAppender(obj).index()

var resultState = state
if (!state.containsMultipleConcreteOrOuterLocations(instanceInfo)) {
if (isFieldStore && !state.containsMultipleConcreteOrOuterLocations(instanceInfo)) {
resultState = resultState.remove(heapAlias)
}

Expand All @@ -618,10 +622,10 @@ class DSUAliasAnalysis(
}

private fun evalArrayStore(stmt: Stmt.ArrayStore, state: State): State =
evalHeapStore(stmt.instance, stmt.value, state, ::createArrayAlias)
evalHeapStore(isFieldStore = false, stmt.instance, stmt.value, state, ::createArrayAlias)

private fun evalFieldStore(stmt: Stmt.FieldStore, state: State): State =
evalHeapStore(stmt.instance, stmt.value, state) { createFieldAlias(it, stmt.field) }
evalHeapStore(isFieldStore = true, stmt.instance, stmt.value, state) { createFieldAlias(it, stmt.field) }

private fun State.containsMultipleConcreteOrOuterLocations(instance: AAInfo): Boolean =
containsMultipleConcreteOrOuterLocations(instance.index(), IntOpenHashSet())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.opentaint.dataflow.jvm.ap.ifds.alias

import it.unimi.dsi.fastutil.ints.IntOpenHashSet
import org.opentaint.dataflow.jvm.ap.ifds.JIRLocalAliasAnalysis.AliasAccessor.Field
import org.opentaint.dataflow.jvm.ap.ifds.alias.DSUAliasAnalysis.State
import org.opentaint.dataflow.jvm.ap.ifds.alias.LocalAlias.SimpleLoc
import java.util.IdentityHashMap

internal class StateBuilder(
private val manager: AAInfoManager,
private val strategy: DSUAliasAnalysis.DsuMergeStrategy
) {
private var state = State.empty(manager, strategy)

internal val created = IdentityHashMap<AAInfo, Unit>()

fun local(idx: Int): LocalAlias = create(
SimpleLoc(RefValue.Local(idx, ContextInfo.rootContext))
)

fun outerThis(): LocalAlias = create(
SimpleLoc(RefValue.This(isOuter = true))
)

fun arg(idx: Int): LocalAlias = create(
SimpleLoc(RefValue.Arg(idx))
)

fun unknown(originalIdx: Int): Unknown = create(
Unknown(Stmt.Return(value = null, originalIdx = originalIdx), ContextInfo.rootContext)
)

fun arrayAlias(instanceInfo: AAInfo): HeapAlias =
heapAlias(instanceInfo) { i -> HeapAlias(i, ArrayAlias) }

fun fieldAlias(instanceInfo: AAInfo, fieldName: String, isImmutable: Boolean = true): HeapAlias =
heapAlias(instanceInfo) { i ->
HeapAlias(i, FieldAlias(Field("Cls", fieldName, "I"), isImmutable = isImmutable))
}

private fun heapAlias(instance: AAInfo, body: (Int) -> HeapAlias): HeapAlias {
val instanceId = checkedInfoId(instance)
val instanceGroupId = state.aliasGroupId(instanceId)

return create(body(instanceGroupId))
}

private fun <T : AAInfo> create(info: T): T {
created[info] = Unit
return info
}

fun merge(set: Set<AAInfo>) {
val setIds = checkedInfoIds(set)
state = state.mergeAliasSets(setIds)
}

fun remove(set: Set<AAInfo>) {
val setIds = checkedInfoIds(set)
state = state.removeUnsafe(setIds)
}

fun mergeStates(vararg builders: StateBuilder) {
val states = builders.map { it.state }
this.state = State.merge(manager, strategy, states)

builders.forEach {
created.putAll(it.created)
}
}

fun build(): State = state

internal fun infoId(info: AAInfo): Int = manager.getOrAdd(info)

internal fun infoIds(set: Set<AAInfo>): IntOpenHashSet {
val setIds = IntOpenHashSet()
set.forEach { setIds.add(infoId(it)) }
return setIds
}

private fun checkedInfoId(info: AAInfo): Int {
check(created.containsKey(info)) { "$info doesn't belongs to the current state" }
return manager.getOrAdd(info)
}

private fun checkedInfoIds(set: Set<AAInfo>): IntOpenHashSet {
val setIds = IntOpenHashSet()
set.forEach { setIds.add(checkedInfoId(it)) }
return setIds
}
}
Loading
Loading