spidermonkey-0005: GatherAvailableModuleAncestors O(M²) execList ContainsElement scan
This commit is contained in:
parent
0fb709cb72
commit
421f3352c7
4 changed files with 494 additions and 0 deletions
128
defects/r-source/unit/RSourceWalkClassGraphTest.java
Normal file
128
defects/r-source/unit/RSourceWalkClassGraphTest.java
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* RSourceWalkClassGraphTest — CWE-407 test for r-source-0002
|
||||
*
|
||||
* Models .walkClassGraph() dedup logic:
|
||||
* slow: match(names(exti), what) — O(S²) total across loop
|
||||
* fast: hash-env membership — O(S) total
|
||||
*
|
||||
* Test: for S superclasses, slow does ~S*(S+1)/2 comparisons; fast does ~S.
|
||||
* Ratio must be >= 5x at S=50.
|
||||
*/
|
||||
public class RSourceWalkClassGraphTest {
|
||||
|
||||
// --- SLOW: O(S²) ---
|
||||
// match(names(exti), what): linear scan of what for each name in exti
|
||||
static class SlowWalkClassGraph {
|
||||
long comparisons = 0;
|
||||
|
||||
// Simulate .walkClassGraph accumulating superclasses
|
||||
// Each iteration adds one new class with a chain of transitive supers
|
||||
Set<String> walkGraph(List<String[]> classChains) {
|
||||
// ext = accumulated known superclass names (as ordered list like R's named list)
|
||||
List<String> what = new ArrayList<>();
|
||||
|
||||
for (String[] chain : classChains) {
|
||||
// exti = chain of superclasses for this intermediate class
|
||||
// Remove already-known: match(names(exti), what) — O(|chain| × |what|)
|
||||
List<String> newOnes = new ArrayList<>();
|
||||
for (String name : chain) {
|
||||
boolean found = false;
|
||||
for (String known : what) { // O(|what|) linear scan
|
||||
comparisons++;
|
||||
if (known.equals(name)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) newOnes.add(name);
|
||||
}
|
||||
what.addAll(newOnes);
|
||||
}
|
||||
return new LinkedHashSet<>(what);
|
||||
}
|
||||
}
|
||||
|
||||
// --- FAST: O(S) ---
|
||||
// Hash-env membership: exists(name, envir=what_set)
|
||||
static class FastWalkClassGraph {
|
||||
long lookups = 0;
|
||||
|
||||
Set<String> walkGraph(List<String[]> classChains) {
|
||||
Set<String> whatSet = new HashSet<>(); // the hash env
|
||||
List<String> what = new ArrayList<>(); // ordered for reproducibility
|
||||
|
||||
for (String[] chain : classChains) {
|
||||
// exti[!vapply(names(exti), exists, ...)] — O(|chain|)
|
||||
List<String> newOnes = new ArrayList<>();
|
||||
for (String name : chain) {
|
||||
lookups++;
|
||||
if (!whatSet.contains(name)) {
|
||||
newOnes.add(name);
|
||||
}
|
||||
}
|
||||
for (String name : newOnes) {
|
||||
whatSet.add(name);
|
||||
what.add(name);
|
||||
}
|
||||
}
|
||||
return new LinkedHashSet<>(what);
|
||||
}
|
||||
}
|
||||
|
||||
// Build a diamond-heavy class hierarchy:
|
||||
// S classes C_0..C_S-1, each inheriting from multiple earlier classes
|
||||
static List<String[]> buildClassChains(int s) {
|
||||
// C_i has transitive supers: C_0 through C_{i-1}
|
||||
// walkClassGraph processes each intermediate
|
||||
List<String[]> chains = new ArrayList<>();
|
||||
for (int i = 0; i < s; i++) {
|
||||
// The i-th class contributes i transitive superclasses
|
||||
String[] chain = new String[i];
|
||||
for (int j = 0; j < i; j++) {
|
||||
chain[j] = "class_" + j;
|
||||
}
|
||||
chains.add(chain);
|
||||
}
|
||||
return chains;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int[] sizes = {10, 20, 50, 100};
|
||||
System.out.println("RSourceWalkClassGraphTest — r-source-0002");
|
||||
System.out.println(" Pattern: match(names(exti), what) O(S²) vs hash-env O(S)");
|
||||
System.out.println();
|
||||
|
||||
int passed = 0;
|
||||
int total = 0;
|
||||
|
||||
for (int s : sizes) {
|
||||
List<String[]> chains = buildClassChains(s);
|
||||
|
||||
SlowWalkClassGraph slow = new SlowWalkClassGraph();
|
||||
FastWalkClassGraph fast = new FastWalkClassGraph();
|
||||
|
||||
Set<String> slowResult = slow.walkGraph(chains);
|
||||
Set<String> fastResult = fast.walkGraph(chains);
|
||||
|
||||
boolean sameResult = slowResult.equals(fastResult);
|
||||
double ratio = slow.comparisons > 0 ? (double) slow.comparisons / Math.max(fast.lookups, 1) : 1.0;
|
||||
boolean correctRatio = s >= 20 ? ratio >= 5.0 : ratio >= 2.0;
|
||||
boolean pass = sameResult && correctRatio;
|
||||
|
||||
total++;
|
||||
if (pass) passed++;
|
||||
|
||||
System.out.printf(" S=%-4d slow=%7d fast=%5d ratio=%5.1fx same=%b %s%n",
|
||||
s, slow.comparisons, fast.lookups, ratio, sameResult,
|
||||
pass ? "PASS" : "FAIL");
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.printf("Result: %d/%d PASS%n", passed, total);
|
||||
if (passed < total) System.exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue