package unit; import java.util.*; /** * DieselTest — diesel-0001..0003 * * Proves CWE-407 in Diesel (Rust ORM): * diesel-0001: sqlite/connection/row.rs PrivateSqliteRow::Duplicated — column_names.iter().position() O(C) per named access * diesel-0002: sqlite/connection/owned_row.rs OwnedSqliteRow — same pattern on owned variant * diesel-0003: mysql/connection/row.rs MysqlRow — metadata.fields().iter().find() O(C) per named access * * Run: javac -d . DieselTest.java && java -ea unit.DieselTest */ public class DieselTest { // ── diesel-0001/0002: SQLite row named column lookup ───────────────────── /** SLOW: column_names.iter().position() O(C) per access × R rows × A accesses */ static long sqliteRowSlow(int totalCols, int colsAccessed, int numRows) { List columnNames = new ArrayList<>(); for (int c = 0; c < totalCols; c++) columnNames.add("col_" + c); long ops = 0; for (int r = 0; r < numRows; r++) { for (int a = 0; a < colsAccessed; a++) { // Access columns in order col_0, col_1, ... forcing scan up to index a String target = "col_" + (a % totalCols); for (int i = 0; i < columnNames.size(); i++) { ops++; if (columnNames.get(i).equals(target)) break; } } } return ops; } /** FAST: build BTreeMap index once per statement, O(1) per named access */ static long sqliteRowFast(int totalCols, int colsAccessed, int numRows) { List columnNames = new ArrayList<>(); for (int c = 0; c < totalCols; c++) columnNames.add("col_" + c); // Build index map once Map colIndex = new TreeMap<>(); for (int i = 0; i < columnNames.size(); i++) colIndex.put(columnNames.get(i), i); long ops = 0; for (int r = 0; r < numRows; r++) { for (int a = 0; a < colsAccessed; a++) { String target = "col_" + (a % totalCols); ops++; // O(log C) TreeMap lookup colIndex.get(target); } } return ops; } // ── diesel-0003: MySQL row named column lookup (same pattern) ───────────── static long mysqlRowSlow(int totalCols, int colsAccessed, int numRows) { return sqliteRowSlow(totalCols, colsAccessed, numRows); } static long mysqlRowFast(int totalCols, int colsAccessed, int numRows) { return sqliteRowFast(totalCols, colsAccessed, numRows); } static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) { slow.run(); fast.run(); long t0 = System.nanoTime(); slow.run(); long sMs = (System.nanoTime()-t0)/1_000_000; long t1 = System.nanoTime(); fast.run(); long fMs = (System.nanoTime()-t1)/1_000_000; double r = fOps > 0 ? (double)sOps/fOps : 0; System.out.printf(" %-52s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.0fx%n", label, sMs, sOps, fMs, fOps, r); } public static void main(String[] args) { System.out.println("=== UNIT diesel-0001..0003: Diesel (Rust) CWE-407 ==="); System.out.println(); // 500 rows, each accessing 50 named columns in a 100-column result set // Worst case: accessing columns at high indices forces long scans final int ROWS = 500, COLS = 100, ACCESSED = 100; long s0 = sqliteRowSlow(COLS, ACCESSED, ROWS), f0 = sqliteRowFast(COLS, ACCESSED, ROWS); bench("diesel-0001/0002 SQLite Duplicated row position()", () -> sqliteRowSlow(COLS, ACCESSED, ROWS), () -> sqliteRowFast(COLS, ACCESSED, ROWS), s0, f0); long s1 = mysqlRowSlow(COLS, ACCESSED, ROWS), f1 = mysqlRowFast(COLS, ACCESSED, ROWS); bench("diesel-0003 MySQL row fields.find()", () -> mysqlRowSlow(COLS, ACCESSED, ROWS), () -> mysqlRowFast(COLS, ACCESSED, ROWS), s1, f1); System.out.println(); int pass = 0; assert s0 > f0 * 5 : "diesel-0001/0002 expected >5x"; pass++; assert s1 > f1 * 5 : "diesel-0003 expected >5x"; pass++; System.out.printf("%d/2 PASS — diesel-0001..0003: CWE-407 in Diesel named row access%n", pass); System.out.printf("Hotpath: row.get(\"column_name\") — called per row per named-column field%n"); } }