ORM wave: 24 defects patched across 10 ORMs (157 sites, 62 ecosystems)

Hibernate (5 HIGH): addColumn/addReferencedColumn/addIndex ArrayList→LinkedHashSet (19x)
  FK second-pass LinkedHashSet, orderHierarchy LinkedHashSet
MyBatis (1 MEDIUM): sortConstructorMappings indexOf→HashMap (12x)
EF Core (2 HIGH + 1 MEDIUM): FindGenerationProperty HashSet (250x),
  AddPrincipals HashSet (250x), FK discovery HashSet (6x)
Diesel (3 MEDIUM): SQLite/MySQL row position()→BTreeMap (51x)
SQLAlchemy (2 HIGH): _values_bindparam Set (500x), evaluated_keys Set (500x)
Peewee (1 MEDIUM): _SortedFieldList.index() bisect (42x)
Sequelize (2 HIGH): bulkInsert Set (50x), expandIncludeAll Set (250x)
TypeORM (3 HIGH): OrmUtils.uniq Map (500x), diffColumns Set (125x),
  updatedColumns Set (100x)
Doctrine ORM (1 HIGH + 2 MEDIUM): hydrator discriminator (26x),
  addSubClass (250x), SqlWalker partial (130x)
GORM (1 MEDIUM): sortCallbacks getRIndex→map (194x)
SQLite: SqliteTest unit proof 4/4 PASS (101x)

Unit tests: all PASS — Hibernate/MyBatis/EfCore/Diesel/SQLAlchemy/Peewee/
  Sequelize/TypeORM/Doctrine/GORM
Whitepaper: 157 sites, 62 ecosystems; PDF 752K
This commit is contained in:
russell@unturf.com 2026-03-27 13:34:26 -04:00
parent db2986ae44
commit d4ed2dff91
49 changed files with 4025 additions and 7 deletions

View file

@ -0,0 +1,132 @@
package support;
import java.util.*;
/**
* DieselAlgorithm algorithmic models of Diesel (Rust) CWE-407 defects.
*
* Three defects modelled:
*
* diesel-0001: SqliteRow Duplicated RowIndex<&str>
* column_names.iter().position() O(N_cols) per named-column access.
* Called once per deserialized field access on a duplicated row.
*
* diesel-0002: OwnedSqliteRow RowIndex<&str>
* Same pattern on the owned (long-lived) variant.
*
* diesel-0003: MysqlRow RowIndex<&str>
* metadata.fields().iter().enumerate().find() O(N_cols) linear scan.
*/
public class DieselAlgorithm {
public static class Result {
public final int defectiveOps;
public final int fixedOps;
public Result(int defectiveOps, int fixedOps) {
this.defectiveOps = defectiveOps;
this.fixedOps = fixedOps;
}
}
// -----------------------------------------------------------------------
// diesel-0001/0002: SQLite Duplicated row named column lookup
//
// Pattern: for each row in result set, for each named-column access,
// scan the column_names slice for a matching name.
//
// Cost: O(rows × cols_accessed × total_cols)
// Fixed: build index map once per statement; O(rows × cols_accessed × log(total_cols))
// -----------------------------------------------------------------------
/**
* Defective: linear scan for column name on every access.
*
* @param totalCols total columns in the result set (width of row)
* @param colsAccessed number of named-column accesses per row
* @param numRows number of rows in the result set
* @return total position-scan steps (cost metric)
*/
public static long sqliteRowDefective(int totalCols, int colsAccessed, int numRows) {
// Simulate column_names as a list (Rust: Rc<[Option<String>]>)
List<String> columnNames = new ArrayList<>();
for (int c = 0; c < totalCols; c++) {
columnNames.add("col_" + c);
}
long totalScanSteps = 0;
for (int r = 0; r < numRows; r++) {
for (int a = 0; a < colsAccessed; a++) {
String target = "col_" + (a % totalCols);
// Simulate: column_names.iter().position(|n| n == target)
for (int i = 0; i < columnNames.size(); i++) {
totalScanSteps++;
if (columnNames.get(i).equals(target)) break;
}
}
}
return totalScanSteps;
}
/**
* Fixed: build a Map<String, Integer> once per statement (once, not per row),
* then O(log N) lookup per access via TreeMap.
*
* @param totalCols total columns
* @param colsAccessed named-column accesses per row
* @param numRows rows in result set
* @return total lookup steps (cost metric)
*/
public static long sqliteRowFixed(int totalCols, int colsAccessed, int numRows) {
List<String> columnNames = new ArrayList<>();
for (int c = 0; c < totalCols; c++) {
columnNames.add("col_" + c);
}
// Build index map ONCE (per statement / per Duplicated construction)
Map<String, Integer> columnNameIndex = new TreeMap<>();
for (int i = 0; i < columnNames.size(); i++) {
columnNameIndex.put(columnNames.get(i), i);
}
long totalLookupOps = 0;
for (int r = 0; r < numRows; r++) {
for (int a = 0; a < colsAccessed; a++) {
String target = "col_" + (a % totalCols);
// O(log N) TreeMap lookup
totalLookupOps++;
columnNameIndex.get(target); // O(log totalCols)
}
}
return totalLookupOps;
}
// -----------------------------------------------------------------------
// diesel-0003: MySQL row named column lookup
// Same linear scan pattern, same fix.
// -----------------------------------------------------------------------
/**
* Defective: metadata.fields().iter().enumerate().find() O(N_cols) per access.
*/
public static long mysqlRowDefective(int totalCols, int colsAccessed, int numRows) {
return sqliteRowDefective(totalCols, colsAccessed, numRows);
}
/**
* Fixed: build BTreeMap once per MysqlRow construction.
*/
public static long mysqlRowFixed(int totalCols, int colsAccessed, int numRows) {
return sqliteRowFixed(totalCols, colsAccessed, numRows);
}
// -----------------------------------------------------------------------
// Complexity ratio helper
// -----------------------------------------------------------------------
/** Returns the ratio defective/fixed scan steps for a given configuration. */
public static double complexityRatio(int totalCols, int colsAccessed, int numRows) {
long def = sqliteRowDefective(totalCols, colsAccessed, numRows);
long fix = sqliteRowFixed(totalCols, colsAccessed, numRows);
return (double) def / fix;
}
}