Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package sample;

public @interface AliasSettings {
int interProcDepth() default 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package sample;

public class BaseSample {

protected Object field;

public Object getField() {
return this.field;
}

public void setField(Object val) {
this.field = val;
}

public static class Box {
public Object value;

public void touchHeap() { }
}

public static Object readValue(Box box) {
return box.value;
}

public static Box makeBox(Object value) {
Box box = new Box();
box.value = value;
return box;
}

public static Box passThroughBox(Box box) {
return box;
}

public static class Nested {
public Box box;

public void touchHeap() { }

public void touchHeapDepth2() { touchHeap(); }
}

public static class Node {
public Node next;
public Object data;
}

public static Object identity(Object x) {
return x;
}

public static void sinkOneValue(Object v) { }

public static void sinkTwoValues(Object v1, Object v2) { }

public static void doNothing() { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package sample.alias;

import sample.AliasSettings;
import sample.BaseSample;

public class CombinedHeapAliasSample extends BaseSample {

static void writeArgThenTouchHeap(Box box, Object src) {
box.value = src;
Object alias = box.value;
box.touchHeap();
sinkOneValue(alias);
}

@AliasSettings(interProcDepth = 1)
static void returnArgField(Box box) {
Object result = readValue(box);
sinkOneValue(result);
}

@AliasSettings(interProcDepth = 1)
static void returnIdentityThenWriteField(Box box, Object src) {
Object tmp = identity(src);
box.value = tmp;
Object result = box.value;
sinkOneValue(result);
}

@AliasSettings(interProcDepth = 1)
static void freshObjectCarriesReturnedArg(Object src) {
Box fresh = makeBox(identity(src));
Object result = fresh.value;
sinkOneValue(result);
}

static void freshObjectCopiesArgumentField(Box srcBox) {
Box fresh = new Box();
fresh.value = srcBox.value;
Object result = fresh.value;
sinkOneValue(result);
}

@AliasSettings(interProcDepth = 1)
static void passThroughReceiverThenReadField(Box box) {
Box alias = passThroughBox(box);
Object result = alias.value;
sinkOneValue(result);
}

@AliasSettings(interProcDepth = 1)
static void nestedWriteReturnAndTouchHeap(Nested nested, Object src) {
nested.box.value = identity(src);
Object alias = readValue(nested.box);
nested.touchHeapDepth2();
sinkOneValue(alias);
}

static void overwriteFieldWithFreshObject(Box box, Object src) {
box.value = src;
Box fresh = new Box();
fresh.value = new Object();
box.value = fresh.value;
Object result = fresh.value;
sinkOneValue(result);
}

@AliasSettings(interProcDepth = 1)
static void returnFreshBoxThenAliasField(Box box, Object src) {
box.value = src;
Box other = makeBox(box.value);
Object result = other.value;
sinkOneValue(result);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
package sample.alias;

public class HeapAliasSample {
import sample.BaseSample;

static class Box {
Object value;
}

static class Nested {
Box box;
}

static class Node {
Node next;
Object data;
}
public class HeapAliasSample extends BaseSample {

static void readArgField(Box box) {
Object dst = box.value;
Expand Down Expand Up @@ -112,7 +101,4 @@ static void aliasedReceiverFieldWrite(Box b1, Box b2, Object src) {
Object dst = b2.value;
sinkOneValue(dst);
}

static void sinkOneValue(Object v) { }
static void sinkTwoValues(Object v1, Object v2) { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,25 @@

import java.util.Collections;
import java.util.List;
import sample.AliasSettings;
import sample.BaseSample;

public class InterProcAliasSample {

Object field;

Object getField() {
return this.field;
}

void setField(Object val) {
this.field = val;
}
public class InterProcAliasSample extends BaseSample {

@AliasSettings(interProcDepth = 1)
void testGetterAlias() {
Object result = getField();
sinkOneValue(result);
}

@AliasSettings(interProcDepth = 1)
void testSetterThenGetter(Object src) {
setField(src);
Object result = getField();
sinkOneValue(result);
}

static Object identity(Object x) {
return x;
}

@AliasSettings(interProcDepth = 1)
static void testIdentityCall(Object src) {
Object result = identity(src);
sinkOneValue(result);
Expand All @@ -47,6 +38,4 @@ static void testExternalCallInvalidatesHeap(Object src) {
Object dst = arr[0];
sinkOneValue(dst);
}

static void sinkOneValue(Object v) { }
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package sample.alias;

import java.util.List;
import sample.BaseSample;

public class LoopAliasSample {

static class Node {
Node next;
Object data;
}
public class LoopAliasSample extends BaseSample {

static void aliasInLoop(Object a, Object b) {
Object cur = a;
Expand Down Expand Up @@ -62,7 +58,4 @@ static void nodeNextLoopData(Node head) {
Object data = cur.data;
sinkOneValue(data);
}

static void sinkOneValue(Object v) { }
static void doNothing() { }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.opentaint.dataflow.jvm.ap.ifds

import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import org.opentaint.dataflow.ap.ifds.AccessPathBase
import org.opentaint.dataflow.jvm.ap.ifds.alias.JIRIntraProcAliasAnalysis
import org.opentaint.ir.api.common.cfg.CommonInst
Expand All @@ -20,38 +21,61 @@ class JIRLocalAliasAnalysis(
val aliasAnalysisInterProcCallDepth: Int = 0,
)

private val aliasInfo by lazy { compute() }
private val mayAliasInfo by lazy { computeMay() }
private val mustAliasInfo by lazy { computeMust() }

class MethodAliasInfo(
val aliasBeforeStatement: Array<Int2ObjectOpenHashMap<Array<Any>>?>,
val aliasAfterStatement: Array<Int2ObjectOpenHashMap<Array<Any>>?>,
)

class MethodMustAliasInfo(
val aliasBeforeStatement: Array<Object2ObjectOpenHashMap<AccessPathBase, Array<Any>>?>,
val aliasAfterStatement: Array<Object2ObjectOpenHashMap<AccessPathBase, Array<Any>>?>,
)

private fun getLocalVarAliases(
alias: Array<Int2ObjectOpenHashMap<Array<Any>>?>,
instIdx: Int, base: AccessPathBase.LocalVar
): List<AliasInfo>? =
alias[instIdx]?.getOrDefault(base.idx, null)?.filter {
it !is AliasApInfo || it.accessors.isNotEmpty() || it.base != base
it !is AccessPathBase || it != base
}?.map { it.wrapAliasInfo() }

private fun getAccessPathBaseAliases(
alias: Array<Object2ObjectOpenHashMap<AccessPathBase, Array<Any>>?>,
instIdx: Int, base: AccessPathBase
): List<AliasInfo>? =
alias[instIdx]?.getOrDefault(base, null)?.filter {
it !is AccessPathBase || it != base
}?.map { it.wrapAliasInfo() }

fun findMustAlias(base: AccessPathBase, statement: CommonInst): List<AliasInfo>? {
val idx = languageManager.getInstIndex(statement)
return getAccessPathBaseAliases(mustAliasInfo.aliasBeforeStatement, idx, base)
}

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

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

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

private fun computeMay(): MethodAliasInfo {
return JIRIntraProcAliasAnalysis(entryPoint, graph, callResolver, languageManager, params).computeMay(localVariableReachability)
}

private fun compute(): MethodAliasInfo {
return JIRIntraProcAliasAnalysis(entryPoint, graph, callResolver, languageManager, params).compute(localVariableReachability)
private fun computeMust(): MethodMustAliasInfo {
return JIRIntraProcAliasAnalysis(entryPoint, graph, callResolver, languageManager, params).computeMust(localVariableReachability)
}

sealed interface AliasAccessor {
Expand Down Expand Up @@ -85,6 +109,14 @@ class JIRLocalAliasAnalysis(
return result
}

fun wrapAllInfo(info: Object2ObjectOpenHashMap<AccessPathBase, Array<Any>>): Object2ObjectOpenHashMap<AccessPathBase, List<AliasInfo>> {
val result = Object2ObjectOpenHashMap<AccessPathBase, List<AliasInfo>>()
for ((key, aliases) in info) {
result.put(key, List(aliases.size) { aliases[it].wrapAliasInfo() })
}
return result
}

fun unwrapAllInfo(info: Int2ObjectOpenHashMap<List<AliasInfo>>): Int2ObjectOpenHashMap<Array<Any>> {
val result = Int2ObjectOpenHashMap<Array<Any>>(info.size, 0.99f)
val iter = info.int2ObjectEntrySet().fastIterator()
Expand All @@ -96,5 +128,17 @@ class JIRLocalAliasAnalysis(
}
return result
}

fun unwrapAllInfo(info: Object2ObjectOpenHashMap<AccessPathBase, List<AliasInfo>>): Object2ObjectOpenHashMap<AccessPathBase, Array<Any>> {
val result = Object2ObjectOpenHashMap<AccessPathBase, Array<Any>>(info.size, 0.99f)
val iter = info.object2ObjectEntrySet().fastIterator()
while (iter.hasNext()) {
val entry = iter.next()
val value = entry.value
val unwrapped = Array(value.size) { value[it].unwrap() }
result.put(entry.key, unwrapped)
}
return result
}
}
}
Loading
Loading