B&W print-friendly diagrams + tinkerpop-0001 + wave-3 proof sections. Squash of 94 local commits onto remote master.
177 lines
6.8 KiB
Java
177 lines
6.8 KiB
Java
package unit;
|
||
|
||
import java.util.ArrayList;
|
||
import java.util.HashSet;
|
||
|
||
/**
|
||
* Unit tests modelling CWE-407 defects in LLVM:
|
||
*
|
||
* llvm-0002 — AliasSet::MemoryLocs: SmallVector + is_contained O(N)
|
||
* vs DenseSet::count O(1).
|
||
* Modelled as: outer loop over N memory accesses, inner
|
||
* ArrayList.contains() for dedup vs HashSet.contains().
|
||
*
|
||
* llvm-0003 — LCSSA isExitBlock: SmallVectorImpl + is_contained O(X)
|
||
* vs SmallPtrSet::count O(1).
|
||
* Modelled as: worklist of U uses, each calls
|
||
* ArrayList.contains() for X exit blocks vs HashSet.contains().
|
||
*
|
||
* Pure Java stdlib, instrumented operation counts.
|
||
*/
|
||
public class LlvmAliasSetTest {
|
||
|
||
// -----------------------------------------------------------------------
|
||
// llvm-0002 helpers
|
||
// -----------------------------------------------------------------------
|
||
|
||
/** Simulate defective path: N accesses, dedup via ArrayList.contains(). */
|
||
static long aliasSetDefective(int nAccesses, int maxLocs) {
|
||
ArrayList<Long> memoryLocs = new ArrayList<>();
|
||
long ops = 0;
|
||
for (int i = 0; i < nAccesses; i++) {
|
||
long loc = i % maxLocs;
|
||
// O(current size) scan — mirrors is_contained(MemoryLocs, MemLoc)
|
||
boolean found = false;
|
||
for (int j = 0; j < memoryLocs.size(); j++) {
|
||
ops++;
|
||
if (memoryLocs.get(j).equals(loc)) { found = true; break; }
|
||
}
|
||
if (!found) memoryLocs.add(loc);
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
/** Simulate fixed path: N accesses, dedup via HashSet.contains(). */
|
||
static long aliasSetFixed(int nAccesses, int maxLocs) {
|
||
HashSet<Long> memoryLocs = new HashSet<>();
|
||
long ops = 0;
|
||
for (int i = 0; i < nAccesses; i++) {
|
||
long loc = i % maxLocs;
|
||
// O(1) — mirrors DenseSet::count(MemLoc)
|
||
ops++;
|
||
memoryLocs.add(loc);
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
// -----------------------------------------------------------------------
|
||
// llvm-0003 helpers
|
||
// -----------------------------------------------------------------------
|
||
|
||
/** Simulate defective LCSSA: U uses × X exit blocks, ArrayList scan. */
|
||
static long lcssaDefective(int nUses, int nExitBlocks) {
|
||
ArrayList<Integer> exitBlocks = new ArrayList<>();
|
||
for (int i = 0; i < nExitBlocks; i++) exitBlocks.add(i);
|
||
long ops = 0;
|
||
for (int u = 0; u < nUses; u++) {
|
||
int userBB = u % nExitBlocks;
|
||
// O(X) per use — mirrors is_contained(ExitBlocks, UserBB)
|
||
for (int j = 0; j < exitBlocks.size(); j++) {
|
||
ops++;
|
||
if (exitBlocks.get(j).equals(userBB)) break;
|
||
}
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
/** Simulate fixed LCSSA: U uses × X exit blocks, HashSet lookup. */
|
||
static long lcssaFixed(int nUses, int nExitBlocks) {
|
||
HashSet<Integer> exitBlockSet = new HashSet<>();
|
||
for (int i = 0; i < nExitBlocks; i++) exitBlockSet.add(i);
|
||
long ops = 0;
|
||
for (int u = 0; u < nUses; u++) {
|
||
int userBB = u % nExitBlocks;
|
||
// O(1) — mirrors SmallPtrSet::count(UserBB)
|
||
ops++;
|
||
exitBlockSet.contains(userBB);
|
||
}
|
||
return ops;
|
||
}
|
||
|
||
// -----------------------------------------------------------------------
|
||
// Test methods
|
||
// -----------------------------------------------------------------------
|
||
|
||
/**
|
||
* llvm-0002: defective op count must grow quadratically with saturation.
|
||
* At N=200 accesses, maxLocs=250: defective scans accumulate O(N×locs).
|
||
*/
|
||
static void testAliasSetDefectiveCountGrows() {
|
||
long opsSmall = aliasSetDefective(50, 250);
|
||
long opsFull = aliasSetDefective(200, 250);
|
||
// Quadratic growth: opsFull should be >> 4× opsSmall
|
||
assert opsFull > opsSmall * 4
|
||
: "llvm-0002: expected quadratic growth, got opsSmall=" + opsSmall
|
||
+ " opsFull=" + opsFull;
|
||
System.out.printf("PASS testAliasSetDefectiveCountGrows: opsSmall=%d opsFull=%d ratio=%.1fx%n",
|
||
opsSmall, opsFull, (double) opsFull / opsSmall);
|
||
}
|
||
|
||
/**
|
||
* llvm-0002: fixed op count must be O(N) (one op per access).
|
||
* At N=200 accesses: ops == N.
|
||
*/
|
||
static void testAliasSetFixedCountLinear() {
|
||
int n = 200;
|
||
long ops = aliasSetFixed(n, 250);
|
||
assert ops == n
|
||
: "llvm-0002: expected ops==" + n + " got " + ops;
|
||
System.out.printf("PASS testAliasSetFixedCountLinear: ops=%d (expected %d)%n", ops, n);
|
||
}
|
||
|
||
/**
|
||
* llvm-0002: speedup ratio defective/fixed must exceed 10× at N=200.
|
||
*/
|
||
static void testAliasSetSpeedupRatio() {
|
||
int n = 200, maxLocs = 250;
|
||
long defOps = aliasSetDefective(n, maxLocs);
|
||
long fixOps = aliasSetFixed(n, maxLocs);
|
||
double ratio = (double) defOps / fixOps;
|
||
assert ratio > 10.0
|
||
: "llvm-0002: speedup ratio " + ratio + " not > 10x";
|
||
System.out.printf("PASS testAliasSetSpeedupRatio: defective=%d fixed=%d ratio=%.1fx%n",
|
||
defOps, fixOps, ratio);
|
||
}
|
||
|
||
/**
|
||
* llvm-0003: LCSSA defective op count grows as U×X.
|
||
* At U=100 uses, X=20 exit blocks: ops ≈ U×(X/2) on average.
|
||
*/
|
||
static void testLcssaDefectiveCountGrows() {
|
||
long opsSmall = lcssaDefective(25, 20);
|
||
long opsFull = lcssaDefective(100, 20);
|
||
assert opsFull > opsSmall * 3
|
||
: "llvm-0003: expected super-linear growth, got opsSmall=" + opsSmall
|
||
+ " opsFull=" + opsFull;
|
||
System.out.printf("PASS testLcssaDefectiveCountGrows: opsSmall=%d opsFull=%d ratio=%.1fx%n",
|
||
opsSmall, opsFull, (double) opsFull / opsSmall);
|
||
}
|
||
|
||
/**
|
||
* llvm-0003: speedup ratio defective/fixed must exceed 5× at U=100, X=20.
|
||
*/
|
||
static void testLcssaSpeedupRatio() {
|
||
int nUses = 100, nExitBlocks = 20;
|
||
long defOps = lcssaDefective(nUses, nExitBlocks);
|
||
long fixOps = lcssaFixed(nUses, nExitBlocks);
|
||
double ratio = (double) defOps / fixOps;
|
||
assert ratio > 5.0
|
||
: "llvm-0003: speedup ratio " + ratio + " not > 5x";
|
||
System.out.printf("PASS testLcssaSpeedupRatio: defective=%d fixed=%d ratio=%.1fx%n",
|
||
defOps, fixOps, ratio);
|
||
}
|
||
|
||
// -----------------------------------------------------------------------
|
||
// Main
|
||
// -----------------------------------------------------------------------
|
||
|
||
public static void main(String[] args) {
|
||
System.out.println("=== LlvmAliasSetTest ===");
|
||
testAliasSetDefectiveCountGrows();
|
||
testAliasSetFixedCountLinear();
|
||
testAliasSetSpeedupRatio();
|
||
testLcssaDefectiveCountGrows();
|
||
testLcssaSpeedupRatio();
|
||
System.out.println("All tests passed.");
|
||
}
|
||
}
|