Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a41c0fe
WIP must alias
DanielELog Mar 20, 2026
b941a4a
Add tests for must alias analysis
DanielELog Mar 25, 2026
f7d8ed8
Finalize must alias addition
DanielELog Apr 1, 2026
c4211a0
Add must alias to unresolved call propagation
DanielELog Apr 1, 2026
d1a8ba8
Fix fact splitting
DanielELog Apr 1, 2026
5a3ee2e
Fix must alias fact revival
DanielELog Apr 3, 2026
3730ae3
Add simple semgrep test for must alias
DanielELog Apr 3, 2026
bb4df5f
Add example tests for must alias
DanielELog Apr 8, 2026
0466a12
Fix alias application on call instance
DanielELog Apr 9, 2026
1e2ddeb
Fix original base filtering from alias group
DanielELog Apr 9, 2026
3a9f430
Fix after rebase
Saloed Apr 22, 2026
a40611d
Remove irrelevant check
DanielELog May 13, 2026
2d25009
Fix incorrect commit merge
DanielELog May 25, 2026
adc55e2
Fix alias heap invalidation calculation
DanielELog May 26, 2026
95ed603
Fix variety of bugs
DanielELog May 26, 2026
807db27
Fix heap invalidation condition
DanielELog May 27, 2026
4497f45
Use heap invalidation for must-alias only
DanielELog May 29, 2026
6cd5efa
Add debug-aware cancellation duration
DanielELog May 29, 2026
6c3c2a9
Use mustAliasAfterStatement for calls
DanielELog Jun 3, 2026
daeafe5
Fixes
DanielELog Jun 3, 2026
d7e5066
Add test for alias necessity for field chains
DanielELog Jun 3, 2026
41884e1
Fix incorrect rebase
DanielELog Jun 3, 2026
a07608a
Don't use mustAliasAfterStatement to avoid false negatives
DanielELog Jun 5, 2026
2bd0e9b
debug
DanielELog Jun 10, 2026
523abc0
wip LValue alias
DanielELog Jun 19, 2026
5a0219e
wip LValue alias 2
DanielELog Jun 23, 2026
98495f5
wip LValue alias 3
DanielELog Jun 24, 2026
a5aece3
wip LValue alias 4
DanielELog Jun 24, 2026
f40c8e9
wip LValue alias 5
DanielELog Jun 24, 2026
34bbc14
wip LValue alias 6
DanielELog Jun 24, 2026
0182e9a
wip LValue alias 7
DanielELog Jun 25, 2026
e69bc91
cleanup debug stuff
DanielELog Jun 25, 2026
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
@@ -1,5 +1,8 @@
package org.opentaint.dataflow.util

import java.lang.management.ManagementFactory
import kotlin.time.Duration

class Cancellation {
class Cancelled : Exception("Operation cancelled") {
override fun fillInStackTrace(): Throwable = this
Expand All @@ -22,4 +25,18 @@ class Cancellation {
if (isActive) return
throw Cancelled()
}

companion object {
private val isDebugActive = lazy { getDebuggerAttachment() }

private fun getDebuggerAttachment() =
ManagementFactory.getRuntimeMXBean().inputArguments
.any { it.contains("-agentlib:jdwp") || it.contains("-Xdebug") }

fun getActiveDuration(duration: Duration) =
if (isDebugActive.value)
Duration.INFINITE
else
duration
}
}
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,67 @@
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 class Box2 {
public Box field1;
public Box field2;
}

public static class BoxArray2 {
public Box[] array1;
public Box[] array2;
}

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,21 +1,24 @@
package sample.alias;

import java.nio.ByteBuffer;
import sample.AliasSettings;
import sample.BaseSample;

public final class FlakyAliasSample {
public final class FlakyAliasSample extends BaseSample {

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

private Pooled<ByteBuffer> buffer;

static void sinkOneValue(Object v) { }

@AliasSettings(interProcDepth = 1)
public int write(java.nio.ByteBuffer src) {
Object copyForNonEmptyAlias = identity(src);
java.nio.ByteBuffer[] arr = new java.nio.ByteBuffer[]{src};
flushBufferWithUserData(arr);
sinkOneValue(arr);
sinkOneValue(copyForNonEmptyAlias);
identity(arr);
return 0;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package sample.alias;

import sample.AliasSettings;

public final class HeaderValuesHangSample {

public static void sinkOneValue(Object v) {}

String[] value;

@AliasSettings(interProcDepth = 1)
public void addAllEntry() {
ElementBox box = new ElementBox();
for (int i = 0; i < 1; i++) {
Expand Down
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 @@ -81,6 +70,18 @@ static void nodeTraversal(Node node) {
sinkOneValue(cur);
}

static void aliasFieldWrite(Box2 box2, Object a) {
box2.field1 = box2.field2;
box2.field1.value = a;
sinkOneValue(box2.field2.value);
}

static void aliasArrayWrite(BoxArray2 box2, Object a) {
box2.array1 = box2.array2;
box2.array1[0].value = a;
sinkOneValue(box2.array2[0].value);
}

static void nodeTraversalData(Node node) {
Node cur = node;
while (cur.next != null) {
Expand Down Expand Up @@ -112,7 +113,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() { }
}
Loading
Loading