package unit; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Models rustc's is_target_feature_call_safe() — * checks whether all features required by the callee are present in the caller's body. * * SLOW: O(C × B) — for each callee feature, scan all body features linearly. * FAST: O(C + B) — build a HashSet from body features once, then O(1) per callee lookup. * * CWE-407: compiler/rustc_middle/src/ty/context.rs:1323-1325 */ public class TargetFeatureCallSafeAlgorithm { // ------------------------------------------------------------------------- // Slow (defective) implementation — mirrors current rustc code // ------------------------------------------------------------------------- static class SlowChecker { long linearScans = 0; /** * Returns true if all callee features are present in bodyFeatures. * O(callee.size() × body.size()) — Vec nested linear scan. */ boolean isSafe(List calleeFeatures, List bodyFeatures) { for (String callee : calleeFeatures) { boolean found = false; for (String body : bodyFeatures) { linearScans++; if (body.equals(callee)) { found = true; break; } } if (!found) return false; } return true; } } // ------------------------------------------------------------------------- // Fast (fixed) implementation — HashSet for O(1) membership // ------------------------------------------------------------------------- static class FastChecker { long hashLookups = 0; /** * Returns true if all callee features are present in bodyFeatures. * O(C + B) — build HashSet once, then O(1) per callee feature. */ boolean isSafe(List calleeFeatures, List bodyFeatures) { Set bodySet = new HashSet<>(bodyFeatures); for (String callee : calleeFeatures) { hashLookups++; if (!bodySet.contains(callee)) return false; } return true; } } // ------------------------------------------------------------------------- // Test helpers // ------------------------------------------------------------------------- static int passed = 0; static int total = 0; static void check(String desc, boolean cond) { total++; if (cond) { passed++; System.out.printf(" PASS %s%n", desc); } else { System.out.printf(" FAIL %s%n", desc); } } /** Simulate x86-64 target features (subset of actual rustc list). */ static List buildPlatformFeatures(int count) { String[] base = { "avx512f", "avx512cd", "avx512bw", "avx512dq", "avx512vl", "avx512ifma", "avx512vbmi", "avx512vnni", "avx512bf16", "avx512vp2intersect", "avx2", "avx", "fma", "bmi1", "bmi2", "lzcnt", "popcnt", "sse4.1", "sse4.2", "sse4a", "ssse3", "sse3", "sse2", "sse", "aes", "pclmulqdq", "sha", "rdrnd", "rdseed", "adx", "f16c", "fxsr", "xsave", "xsaveopt", "xsavec", "xsaves", "cx16", "sahf", "movbe", "cmpxchg16b", "clflushopt", "clwb", "rtm", "hle", "tbm", "3dnow", "3dnowa", "mmx", "abm", "ermsb", "fsrm", "vpclmulqdq", "vaes", "gfni", "avxvnni", "amx-tile", "amx-int8", "amx-bf16", "amx-fp16", "serialize", "tsxldtrk", "uintr", "kl", "widekl", }; List result = new ArrayList<>(); for (int i = 0; i < Math.min(count, base.length); i++) { result.add(base[i]); } return result; } public static void main(String[] args) { System.out.println("TargetFeatureCallSafeAlgorithm — CWE-407 unit test"); System.out.println("rustc-0003: is_target_feature_call_safe O(C×B) → O(C+B)"); System.out.println(); SlowChecker slow = new SlowChecker(); FastChecker fast = new FastChecker(); // --- Correctness: safe call (callee subset of body) --- { List callee = List.of("avx2", "bmi1", "popcnt"); List body = List.of("avx2", "avx", "bmi1", "bmi2", "popcnt", "sse4.1"); boolean slowResult = slow.isSafe(callee, body); boolean fastResult = fast.isSafe(callee, body); check("safe-call: slow returns true", slowResult); check("safe-call: fast returns true", fastResult); check("safe-call: results agree", slowResult == fastResult); } // --- Correctness: unsafe call (callee has feature body lacks) --- { List callee = List.of("avx512f", "avx512bw"); List body = List.of("avx2", "avx", "bmi1"); boolean slowResult = slow.isSafe(callee, body); boolean fastResult = fast.isSafe(callee, body); check("unsafe-call: slow returns false", !slowResult); check("unsafe-call: fast returns false", !fastResult); check("unsafe-call: results agree", slowResult == fastResult); } // --- Correctness: empty callee (always safe) --- { List callee = List.of(); List body = List.of("avx2"); boolean slowResult = slow.isSafe(callee, body); boolean fastResult = fast.isSafe(callee, body); check("empty-callee: slow returns true", slowResult); check("empty-callee: fast returns true", fastResult); } // --- Correctness: empty body, non-empty callee (always unsafe) --- { List callee = List.of("avx2"); List body = List.of(); boolean slowResult = slow.isSafe(callee, body); boolean fastResult = fast.isSafe(callee, body); check("empty-body: slow returns false", !slowResult); check("empty-body: fast returns false", !fastResult); } // --- Performance: O(C×B) vs O(C+B) --- { // Simulate a function with 50 callee features all present at the END of a 60-feature // body — forces slow checker to scan to the last position for each callee feature, // maximising the per-call comparison count to ~C×B. int C = 50; int B = 60; // callee features are the LAST C entries of the B-element body list List fullBody = buildPlatformFeatures(B); List body = new ArrayList<>(fullBody); // callee = last C elements (appear near end of body, maximise scan length) List callee = new ArrayList<>(fullBody.subList(B - C, B)); // Reverse body so callee features are at the back java.util.Collections.reverse(body); // Warm up JIT for (int i = 0; i < 500; i++) slow.isSafe(callee, body); for (int i = 0; i < 500; i++) fast.isSafe(callee, body); // Reset counters slow.linearScans = 0; fast.hashLookups = 0; int RUNS = 20_000; long t0 = System.nanoTime(); for (int i = 0; i < RUNS; i++) slow.isSafe(callee, body); long slowNs = System.nanoTime() - t0; long t1 = System.nanoTime(); for (int i = 0; i < RUNS; i++) fast.isSafe(callee, body); long fastNs = System.nanoTime() - t1; double ratio = (double) slowNs / fastNs; System.out.printf(" INFO C=%d B=%d slow_scans=%d fast_lookups=%d ratio=%.1fx%n", C, B, slow.linearScans, fast.hashLookups, ratio); // Slow: each callee feature is at the back of body → scans many positions each. // Minimum acceptable: at least C*(B/4)*RUNS (conservative lower bound, early-exit aware) check("slow does >> C×RUNS comparisons (linear scan dominates)", slow.linearScans >= (long) C * (B / 4) * RUNS); // Fast: exactly C hash lookups per call check("fast does exactly C×RUNS hash lookups", fast.hashLookups == (long) C * RUNS); // Op ratio: slow does at least B/2 per callee feature, fast does 1 long slowOpsPerRun = slow.linearScans / RUNS; long fastOpsPerRun = fast.hashLookups / RUNS; check("slow op count >> fast op count (>= 10x)", slowOpsPerRun >= fastOpsPerRun * 10); } System.out.println(); System.out.printf("%d/%d PASS%n", passed, total); if (passed != total) System.exit(1); } }