undefect. CWE-407 — 92 sites, 42 ecosystems
B&W print-friendly diagrams + tinkerpop-0001 + wave-3 proof sections. Squash of 94 local commits onto remote master.
This commit is contained in:
parent
0a580b313d
commit
db29a08762
1311 changed files with 371202 additions and 1188 deletions
34
defects/octave/patch/octave-0001-vecdim-binary-search.patch
Normal file
34
defects/octave/patch/octave-0001-vecdim-binary-search.patch
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
diff --git a/libinterp/corefcn/data.cc b/libinterp/corefcn/data.cc
|
||||
index a1b2c3d..d4e5f6a 100644
|
||||
--- a/libinterp/corefcn/data.cc
|
||||
+++ b/libinterp/corefcn/data.cc
|
||||
@@ -133,9 +133,10 @@ parse_vecdim_arg (const octave_value &dimarg, const Array<octave_value> &arg,
|
||||
// Add remaining dims to permutation vector
|
||||
for (int i = 0; i < ndims; i++)
|
||||
{
|
||||
- if (std::find (vecdim.begin (), vecdim.end (), i)
|
||||
- == vecdim.end ())
|
||||
+ // CWE-407 fix: vecdim is already sorted (std::sort above);
|
||||
+ // std::find ignores the sort and is O(|vecdim|) per iteration.
|
||||
+ // std::binary_search is O(log |vecdim|).
|
||||
+ if (!std::binary_search (vecdim.begin (), vecdim.end (), i))
|
||||
{
|
||||
perm_vec(idx) = i;
|
||||
new_sz(idx) = sz(i);
|
||||
diff --git a/libinterp/corefcn/numeric/max.cc b/libinterp/corefcn/numeric/max.cc
|
||||
index b2c3d4e..e5f6a7b 100644
|
||||
--- a/libinterp/corefcn/numeric/max.cc
|
||||
+++ b/libinterp/corefcn/numeric/max.cc
|
||||
@@ -106,9 +106,10 @@ do_minmax_nd (const octave_value& arg, int dim, bool ismin,
|
||||
// Add remaining dims to permutation vector
|
||||
for (int i = 0; i < ndims; i++)
|
||||
{
|
||||
- if (std::find (vecdim.begin (), vecdim.end (), i)
|
||||
- == vecdim.end ())
|
||||
+ // CWE-407 fix: vecdim is already sorted (std::sort above);
|
||||
+ // std::find ignores the sort and is O(|vecdim|) per iteration.
|
||||
+ // std::binary_search is O(log |vecdim|).
|
||||
+ if (!std::binary_search (vecdim.begin (), vecdim.end (), i))
|
||||
{
|
||||
perm_vec(idx) = i;
|
||||
new_sz(idx) = sz(i);
|
||||
187
defects/octave/unit/OctaveVecdimTest.java
Normal file
187
defects/octave/unit/OctaveVecdimTest.java
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
package unit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Unit tests modelling CWE-407 defect in GNU Octave:
|
||||
*
|
||||
* octave-0001 — data.cc and numeric/max.cc: vecdim is already sorted by
|
||||
* std::sort, but the subsequent loop uses std::find (O(|vecdim|))
|
||||
* instead of std::binary_search (O(log |vecdim|)).
|
||||
*
|
||||
* Modelled as: outer loop over ndims=64 dimensions, inner
|
||||
* ArrayList.contains() (unsorted scan, O(|vecdim|)) vs
|
||||
* Collections.binarySearch() on a sorted list (O(log |vecdim|)).
|
||||
*
|
||||
* Pure Java stdlib, instrumented operation counts.
|
||||
*/
|
||||
public class OctaveVecdimTest {
|
||||
|
||||
/**
|
||||
* Simulate defective path: ndims iterations, std::find scan per iteration.
|
||||
* vecdim has n entries drawn from [0, ndims).
|
||||
*/
|
||||
static long vecdimDefective(int ndims, int vecdimSize) {
|
||||
ArrayList<Integer> vecdim = new ArrayList<>();
|
||||
// Populate sorted vecdim with every other dim (representative subset)
|
||||
for (int i = 0; i < vecdimSize; i++) {
|
||||
vecdim.add(i * (ndims / vecdimSize));
|
||||
}
|
||||
// Mimics std::sort already done — list is sorted
|
||||
Collections.sort(vecdim);
|
||||
|
||||
long ops = 0;
|
||||
for (int i = 0; i < ndims; i++) {
|
||||
// O(|vecdim|) — mirrors std::find(vecdim.begin(), vecdim.end(), i)
|
||||
boolean found = false;
|
||||
for (int j = 0; j < vecdim.size(); j++) {
|
||||
ops++;
|
||||
if (vecdim.get(j).equals(i)) { found = true; break; }
|
||||
// std::find does not exploit sort order; keep scanning past hits
|
||||
// would continue, but we break on first match (same as std::find)
|
||||
}
|
||||
// remaining iterations for elements not in vecdim scan to the end
|
||||
if (!found) {
|
||||
// already counted full scan above — no extra ops needed
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate defective path with full scan (no early exit) to model worst
|
||||
* case where dims not in vecdim cause a full O(|vecdim|) scan.
|
||||
*/
|
||||
static long vecdimDefectiveWorstCase(int ndims, int vecdimSize) {
|
||||
ArrayList<Integer> vecdim = new ArrayList<>();
|
||||
for (int i = 0; i < vecdimSize; i++) {
|
||||
vecdim.add(i * (ndims / vecdimSize));
|
||||
}
|
||||
Collections.sort(vecdim);
|
||||
|
||||
long ops = 0;
|
||||
for (int i = 0; i < ndims; i++) {
|
||||
// Full O(|vecdim|) scan regardless (std::find scans all when not found)
|
||||
for (int j = 0; j < vecdim.size(); j++) {
|
||||
ops++;
|
||||
if (vecdim.get(j).equals(i)) break;
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate fixed path: ndims iterations, Collections.binarySearch per iteration.
|
||||
* Each binarySearch is O(log |vecdim|).
|
||||
*/
|
||||
static long vecdimFixed(int ndims, int vecdimSize) {
|
||||
ArrayList<Integer> vecdim = new ArrayList<>();
|
||||
for (int i = 0; i < vecdimSize; i++) {
|
||||
vecdim.add(i * (ndims / vecdimSize));
|
||||
}
|
||||
Collections.sort(vecdim);
|
||||
|
||||
long ops = 0;
|
||||
for (int i = 0; i < ndims; i++) {
|
||||
// O(log |vecdim|) — mirrors std::binary_search(vecdim.begin(), vecdim.end(), i)
|
||||
int lo = 0, hi = vecdim.size() - 1;
|
||||
while (lo <= hi) {
|
||||
ops++;
|
||||
int mid = (lo + hi) >>> 1;
|
||||
int cmp = vecdim.get(mid).compareTo(i);
|
||||
if (cmp < 0) lo = mid + 1;
|
||||
else if (cmp > 0) hi = mid - 1;
|
||||
else break;
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Test methods
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Defective op count must grow as ndims × |vecdim|.
|
||||
* Confirm: opsLarge > opsSmall × 3 when scaling ndims from 16 to 64.
|
||||
*/
|
||||
static void testDefectiveCountGrows() {
|
||||
long opsSmall = vecdimDefectiveWorstCase(16, 8);
|
||||
long opsFull = vecdimDefectiveWorstCase(64, 32);
|
||||
assert opsFull > opsSmall * 3
|
||||
: "octave-0001: expected super-linear growth, opsSmall=" + opsSmall
|
||||
+ " opsFull=" + opsFull;
|
||||
System.out.printf("PASS testDefectiveCountGrows: opsSmall=%d opsFull=%d ratio=%.1fx%n",
|
||||
opsSmall, opsFull, (double) opsFull / opsSmall);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixed op count must be O(ndims × log|vecdim|).
|
||||
* At ndims=64, vecdimSize=32: ops <= ndims * ceil(log2(32)+1) = 64*6 = 384.
|
||||
*/
|
||||
static void testFixedCountLogBound() {
|
||||
int ndims = 64, vecdimSize = 32;
|
||||
long ops = vecdimFixed(ndims, vecdimSize);
|
||||
long bound = (long) ndims * (long) Math.ceil(Math.log(vecdimSize) / Math.log(2) + 1);
|
||||
assert ops <= bound
|
||||
: "octave-0001: fixed ops=" + ops + " exceeded log bound=" + bound;
|
||||
System.out.printf("PASS testFixedCountLogBound: ops=%d bound=%d%n", ops, bound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Speedup ratio defective/fixed must exceed 5× at ndims=64, vecdimSize=32.
|
||||
*/
|
||||
static void testSpeedupRatio() {
|
||||
int ndims = 64, vecdimSize = 32;
|
||||
long defOps = vecdimDefectiveWorstCase(ndims, vecdimSize);
|
||||
long fixOps = vecdimFixed(ndims, vecdimSize);
|
||||
double ratio = (double) defOps / fixOps;
|
||||
assert ratio > 5.0
|
||||
: "octave-0001: speedup ratio " + ratio + " not > 5x";
|
||||
System.out.printf("PASS testSpeedupRatio: defective=%d fixed=%d ratio=%.1fx%n",
|
||||
defOps, fixOps, ratio);
|
||||
}
|
||||
|
||||
/**
|
||||
* Correctness: defective and fixed paths agree on which dims are excluded.
|
||||
* Both should exclude the same set of dims not present in vecdim.
|
||||
*/
|
||||
static void testCorrectnessAgreement() {
|
||||
int ndims = 64, vecdimSize = 32;
|
||||
ArrayList<Integer> vecdim = new ArrayList<>();
|
||||
for (int i = 0; i < vecdimSize; i++) {
|
||||
vecdim.add(i * (ndims / vecdimSize));
|
||||
}
|
||||
Collections.sort(vecdim);
|
||||
|
||||
ArrayList<Integer> excludedByFind = new ArrayList<>();
|
||||
ArrayList<Integer> excludedByBsearch = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < ndims; i++) {
|
||||
// std::find equivalent
|
||||
if (!vecdim.contains(i)) excludedByFind.add(i);
|
||||
// std::binary_search equivalent
|
||||
if (Collections.binarySearch(vecdim, i) < 0) excludedByBsearch.add(i);
|
||||
}
|
||||
|
||||
assert excludedByFind.equals(excludedByBsearch)
|
||||
: "octave-0001: correctness mismatch: find=" + excludedByFind
|
||||
+ " bsearch=" + excludedByBsearch;
|
||||
System.out.printf("PASS testCorrectnessAgreement: %d dims excluded (identical)%n",
|
||||
excludedByFind.size());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Main
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== OctaveVecdimTest ===");
|
||||
testDefectiveCountGrows();
|
||||
testFixedCountLogBound();
|
||||
testSpeedupRatio();
|
||||
testCorrectnessAgreement();
|
||||
System.out.println("All tests passed.");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue