rustc/swift: CWE-407 scan — rustc CLEAN, swift 1 defect
rustc: Exemplary use of FxHashSet/BitSet/IntervalSet throughout; no linear membership tests on hot paths. swift-0001: LoadableByAddress.cpp StructLoweringState uses SmallVector with std::find for largeLoadableArgs/applies membership — O(I×A) per function, 322x overhead at A=500. Fix: SmallPtrSet shadow.
This commit is contained in:
parent
79a77db4f8
commit
b37db35655
1 changed files with 143 additions and 0 deletions
143
defects/swift/unit/SwiftTest.java
Normal file
143
defects/swift/unit/SwiftTest.java
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 simulation: Swift LoadableByAddress pass linear membership tests.
|
||||
*
|
||||
* The StructLoweringState in LoadableByAddress.cpp uses SmallVector with
|
||||
* std::find for membership tests on largeLoadableArgs, applies, and other
|
||||
* instruction vectors. For each instruction in the function, std::find
|
||||
* performs O(A) linear scan where A = number of large loadable args.
|
||||
*
|
||||
* Defect: O(I x A) where I = instructions, A = large loadable args
|
||||
* Fix: SmallPtrSet shadow for O(1) membership tests -> O(I + A)
|
||||
*
|
||||
* swift-0001: LoadableByAddress largeLoadableArgs/applies linear membership
|
||||
*/
|
||||
public class SwiftTest {
|
||||
|
||||
// --- Defective: SmallVector + std::find pattern ---
|
||||
static long visitApplyDefective(List<Object> largeLoadableArgs,
|
||||
List<Object> funcSigArgs,
|
||||
List<Object> applies,
|
||||
List<Object[]> applyOperands) {
|
||||
long ops = 0;
|
||||
for (Object[] operands : applyOperands) {
|
||||
for (Object operand : operands) {
|
||||
ops++;
|
||||
// std::find(largeLoadableArgs.begin(), ..., currOperand)
|
||||
boolean found = false;
|
||||
for (Object arg : largeLoadableArgs) {
|
||||
ops++;
|
||||
if (arg == operand) { found = true; break; }
|
||||
}
|
||||
if (!found) {
|
||||
// std::find(funcSigArgs.begin(), ..., currOperand)
|
||||
for (Object arg : funcSigArgs) {
|
||||
ops++;
|
||||
if (arg == operand) { found = true; break; }
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
// Dedup check: std::find(applies.begin(), ..., instr)
|
||||
Object instr = operands; // proxy for instruction
|
||||
for (Object a : applies) {
|
||||
ops++;
|
||||
if (a == instr) { found = false; break; }
|
||||
}
|
||||
if (found) applies.add(instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
// --- Fixed: SmallPtrSet shadow for O(1) lookup ---
|
||||
static long visitApplyFixed(Set<Object> largeLoadableArgsSet,
|
||||
Set<Object> funcSigArgsSet,
|
||||
Set<Object> appliesSet,
|
||||
List<Object[]> applyOperands) {
|
||||
long ops = 0;
|
||||
for (Object[] operands : applyOperands) {
|
||||
for (Object operand : operands) {
|
||||
ops++;
|
||||
boolean found = largeLoadableArgsSet.contains(operand);
|
||||
ops++;
|
||||
if (!found) {
|
||||
found = funcSigArgsSet.contains(operand);
|
||||
ops++;
|
||||
}
|
||||
if (found) {
|
||||
Object instr = operands;
|
||||
if (appliesSet.add(instr)) {
|
||||
ops++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Simulate a function with A large loadable args and I apply instructions
|
||||
int[] sizes = {10, 50, 100, 200, 500};
|
||||
|
||||
System.out.println("swift-0001: LoadableByAddress largeLoadableArgs linear membership");
|
||||
System.out.println("=================================================================");
|
||||
System.out.printf("%-8s %-14s %-14s %-10s %-6s%n",
|
||||
"A(args)", "Defective ops", "Fixed ops", "Ratio", "Status");
|
||||
|
||||
boolean allPass = true;
|
||||
for (int A : sizes) {
|
||||
// Create A large loadable args
|
||||
List<Object> largeLoadableArgs = new ArrayList<>();
|
||||
Set<Object> largeLoadableArgsSet = new HashSet<>();
|
||||
List<Object> funcSigArgs = new ArrayList<>();
|
||||
Set<Object> funcSigArgsSet = new HashSet<>();
|
||||
List<Object> applies = new ArrayList<>();
|
||||
Set<Object> appliesSet = new HashSet<>();
|
||||
|
||||
Object[] argPool = new Object[A];
|
||||
for (int i = 0; i < A; i++) {
|
||||
argPool[i] = new Object();
|
||||
largeLoadableArgs.add(argPool[i]);
|
||||
largeLoadableArgsSet.add(argPool[i]);
|
||||
funcSigArgs.add(argPool[i]);
|
||||
funcSigArgsSet.add(argPool[i]);
|
||||
}
|
||||
|
||||
// Create I apply instructions, each with 3 operands from the arg pool
|
||||
int I = A * 2; // instructions proportional to args
|
||||
List<Object[]> applyOperands = new ArrayList<>();
|
||||
Random rng = new Random(42);
|
||||
for (int i = 0; i < I; i++) {
|
||||
Object[] ops = new Object[3];
|
||||
for (int j = 0; j < 3; j++) {
|
||||
ops[j] = argPool[rng.nextInt(A)];
|
||||
}
|
||||
applyOperands.add(ops);
|
||||
}
|
||||
|
||||
long defectOps = visitApplyDefective(
|
||||
new ArrayList<>(largeLoadableArgs),
|
||||
new ArrayList<>(funcSigArgs),
|
||||
new ArrayList<>(applies),
|
||||
applyOperands);
|
||||
long fixedOps = visitApplyFixed(
|
||||
new HashSet<>(largeLoadableArgsSet),
|
||||
new HashSet<>(funcSigArgsSet),
|
||||
new HashSet<>(appliesSet),
|
||||
applyOperands);
|
||||
|
||||
double ratio = (double) defectOps / fixedOps;
|
||||
boolean pass = ratio > 2.0;
|
||||
allPass &= pass;
|
||||
|
||||
System.out.printf("%-8d %-14d %-14d %-10.1f %-6s%n",
|
||||
A, defectOps, fixedOps, ratio, pass ? "PASS" : "FAIL");
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
System.out.println(allPass ? "ALL PASS" : "SOME FAIL");
|
||||
System.exit(allPass ? 0 : 1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue