112 lines
3.7 KiB
Java
112 lines
3.7 KiB
Java
import java.util.*;
|
|
|
|
/**
|
|
* Java simulation of Ruby MRI CWE-407 defect.
|
|
*
|
|
* ruby-0001: class.c do_include_modules_at super chain linear scan O(M*S)
|
|
* For each module to include, walks entire super chain to check if
|
|
* module's method table is already present. O(M * S) total.
|
|
* Fix: st_table (hash set) of method table pointers for O(1) lookup.
|
|
*/
|
|
public class RubyTest {
|
|
|
|
/**
|
|
* Simulate module include with linear super chain scan.
|
|
* DEFECTIVE: O(M * S) — for each of M modules, scan S super entries.
|
|
*/
|
|
static long includeModulesDefective(int numModules, int superChainLen) {
|
|
// Simulate super chain as list of "method table pointers" (ints)
|
|
List<Integer> superChain = new ArrayList<>();
|
|
for (int i = 0; i < superChainLen; i++) {
|
|
superChain.add(i); // existing iclass method tables
|
|
}
|
|
|
|
long ops = 0;
|
|
|
|
// Include M new modules
|
|
for (int m = 0; m < numModules; m++) {
|
|
int moduleMTbl = superChainLen + m; // new module's method table
|
|
boolean found = false;
|
|
|
|
// Linear scan of super chain — O(S)
|
|
for (int s = 0; s < superChain.size(); s++) {
|
|
ops++;
|
|
if (superChain.get(s) == moduleMTbl) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
superChain.add(moduleMTbl); // Insert new iclass
|
|
}
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
/**
|
|
* FIXED: O(M) — hash set for method table membership check.
|
|
*/
|
|
static long includeModulesFixed(int numModules, int superChainLen) {
|
|
List<Integer> superChain = new ArrayList<>();
|
|
Set<Integer> mtblSet = new HashSet<>();
|
|
for (int i = 0; i < superChainLen; i++) {
|
|
superChain.add(i);
|
|
mtblSet.add(i);
|
|
}
|
|
|
|
long ops = 0;
|
|
|
|
for (int m = 0; m < numModules; m++) {
|
|
int moduleMTbl = superChainLen + m;
|
|
ops++; // O(1) hash lookup
|
|
boolean found = mtblSet.contains(moduleMTbl);
|
|
|
|
if (!found) {
|
|
superChain.add(moduleMTbl);
|
|
mtblSet.add(moduleMTbl);
|
|
}
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
static void test0001() {
|
|
System.out.println("=== ruby-0001: do_include_modules_at super chain scan ===");
|
|
|
|
int[][] params = {
|
|
{10, 20}, // M=10 modules, S=20 super chain
|
|
{20, 50}, // M=20, S=50 (typical Rails)
|
|
{30, 80}, // M=30, S=80 (heavy Rails)
|
|
{50, 100}, // M=50, S=100 (extreme)
|
|
};
|
|
|
|
for (int[] p : params) {
|
|
int M = p[0], S = p[1];
|
|
long defOps = includeModulesDefective(M, S);
|
|
long fixOps = includeModulesFixed(M, S);
|
|
double ratio = (double) defOps / fixOps;
|
|
System.out.printf(" M=%2d S=%3d: defective=%6d fixed=%3d ratio=%.1fx%n",
|
|
M, S, defOps, fixOps, ratio);
|
|
if (M >= 20 && ratio < 5.0) {
|
|
throw new AssertionError("Expected ratio >= 5x at M=" + M
|
|
+ " S=" + S + ", got " + ratio);
|
|
}
|
|
}
|
|
|
|
// Verify growth is proportional to M*S
|
|
long ops_20_50 = includeModulesDefective(20, 50);
|
|
long ops_50_100 = includeModulesDefective(50, 100);
|
|
double growth = (double) ops_50_100 / ops_20_50;
|
|
System.out.printf(" Growth (20,50)->(50,100): %.1fx (expect ~5x for O(M*S))%n", growth);
|
|
if (growth < 3.0) {
|
|
throw new AssertionError("Expected M*S growth, got " + growth + "x");
|
|
}
|
|
|
|
System.out.println(" PASS");
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
test0001();
|
|
System.out.println("\nAll Ruby CWE-407 tests PASSED");
|
|
}
|
|
}
|