wave6a/6b: elasticsearch/opensearch/solr/llvm-0004-5/linux-0005-6/gcc-0002/tokio/actix-web + love2d/raylib new defects
This commit is contained in:
parent
a4b0cf4edd
commit
3eebda37e1
38 changed files with 3651 additions and 0 deletions
157
defects/raylib/unit/RaylibRandomSequenceTest.java
Normal file
157
defects/raylib/unit/RaylibRandomSequenceTest.java
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
package unit;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* raylib-0002: LoadRandomSequence O(n²) dedup — CWE-407
|
||||
*
|
||||
* Demonstrates: for each of N values generated, a linear scan of the
|
||||
* previously-accepted values is O(n) per iteration → O(n²) total.
|
||||
* Fix: use a boolean seen[] bitmap (range-bounded) for O(1) membership.
|
||||
*/
|
||||
public class RaylibRandomSequenceTest {
|
||||
|
||||
/**
|
||||
* Slow path: mirrors the raylib fallback in LoadRandomSequence().
|
||||
* Returns the exact number of inner-loop iterations (membership checks).
|
||||
*/
|
||||
static long slowRandomSequence(int count, int min, int max, long seed) {
|
||||
int range = Math.abs(max - min) + 1;
|
||||
assert count <= range : "count must not exceed range";
|
||||
|
||||
int[] values = new int[count];
|
||||
Random rng = new Random(seed);
|
||||
long innerOps = 0;
|
||||
|
||||
int i = 0;
|
||||
while (i < count) {
|
||||
int value = min + rng.nextInt(range);
|
||||
boolean dupValue = false;
|
||||
|
||||
// O(i) linear scan — CWE-407
|
||||
for (int j = 0; j < i; j++) {
|
||||
innerOps++;
|
||||
if (values[j] == value) {
|
||||
dupValue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dupValue) {
|
||||
values[i] = value;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify correctness: all values unique and in [min, max]
|
||||
HashSet<Integer> seen = new HashSet<>();
|
||||
for (int v : values) {
|
||||
assert v >= min && v <= max : "value out of range: " + v;
|
||||
assert seen.add(v) : "duplicate value: " + v;
|
||||
}
|
||||
|
||||
return innerOps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast path: boolean seen[] bitmap — O(1) membership per check.
|
||||
* Returns the number of bitmap probes (each is O(1)).
|
||||
*/
|
||||
static long fastRandomSequence(int count, int min, int max, long seed) {
|
||||
int range = Math.abs(max - min) + 1;
|
||||
assert count <= range : "count must not exceed range";
|
||||
|
||||
int[] values = new int[count];
|
||||
boolean[] seen = new boolean[range]; // FIX raylib-0002
|
||||
Random rng = new Random(seed);
|
||||
long probes = 0;
|
||||
|
||||
int i = 0;
|
||||
while (i < count) {
|
||||
int value = min + rng.nextInt(range);
|
||||
int idx = value - min;
|
||||
probes++; // O(1) bitmap probe
|
||||
if (!seen[idx]) {
|
||||
seen[idx] = true;
|
||||
values[i] = value;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify correctness
|
||||
HashSet<Integer> check = new HashSet<>();
|
||||
for (int v : values) {
|
||||
assert v >= min && v <= max : "value out of range: " + v;
|
||||
assert check.add(v) : "duplicate value: " + v;
|
||||
}
|
||||
|
||||
return probes;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int passed = 0;
|
||||
int total = 0;
|
||||
|
||||
// Test 1: small n — verify slow is O(n²), fast is O(n)
|
||||
{
|
||||
total++;
|
||||
int n = 100, min = 0, max = 999;
|
||||
long seed = 42L;
|
||||
long slowOps = slowRandomSequence(n, min, max, seed);
|
||||
long fastOps = fastRandomSequence(n, min, max, seed);
|
||||
// Slow expected ~n*(n-1)/4 ~ 2475 ops; fast expected ~n + small constant
|
||||
boolean ok = slowOps > fastOps * 5;
|
||||
System.out.printf("Test 1 (n=%d): slow=%d ops, fast=%d ops, ratio=%.1fx — %s%n",
|
||||
n, slowOps, fastOps, (double) slowOps / fastOps, ok ? "PASS" : "FAIL");
|
||||
if (ok) passed++;
|
||||
}
|
||||
|
||||
// Test 2: medium n — ratio should be much larger
|
||||
{
|
||||
total++;
|
||||
int n = 500, min = 0, max = 9999;
|
||||
long seed = 123L;
|
||||
long slowOps = slowRandomSequence(n, min, max, seed);
|
||||
long fastOps = fastRandomSequence(n, min, max, seed);
|
||||
boolean ok = slowOps > fastOps * 50;
|
||||
System.out.printf("Test 2 (n=%d): slow=%d ops, fast=%d ops, ratio=%.1fx — %s%n",
|
||||
n, slowOps, fastOps, (double) slowOps / fastOps, ok ? "PASS" : "FAIL");
|
||||
if (ok) passed++;
|
||||
}
|
||||
|
||||
// Test 3: worst case — count == range (dense selection forces many collisions)
|
||||
{
|
||||
total++;
|
||||
int n = 200, min = 0, max = 199; // count == range: worst case for slow
|
||||
long seed = 7L;
|
||||
long slowOps = slowRandomSequence(n, min, max, seed);
|
||||
long fastOps = fastRandomSequence(n, min, max, seed);
|
||||
// Slow expected ~n²/4 = 10000 ops; fast expected ~n*H(n) ≈ 1060 ops (harmonic)
|
||||
boolean ok = slowOps > fastOps * 5;
|
||||
System.out.printf("Test 3 (n=%d, dense): slow=%d ops, fast=%d ops, ratio=%.1fx — %s%n",
|
||||
n, slowOps, fastOps, (double) slowOps / fastOps, ok ? "PASS" : "FAIL");
|
||||
if (ok) passed++;
|
||||
}
|
||||
|
||||
// Test 4: correctness — outputs must be identical sequences given same seed
|
||||
{
|
||||
total++;
|
||||
int n = 50, min = 10, max = 200;
|
||||
long seed = 99L;
|
||||
|
||||
// We can't compare element-by-element because the two algorithms
|
||||
// process rejections differently per RNG call, so just verify
|
||||
// both produce valid unique sequences independently.
|
||||
long slowOps = slowRandomSequence(n, min, max, seed);
|
||||
long fastOps = fastRandomSequence(n, min, max, seed);
|
||||
boolean ok = slowOps > 0 && fastOps > 0;
|
||||
System.out.printf("Test 4 (correctness, n=%d): slow valid=%b, fast valid=%b — %s%n",
|
||||
n, slowOps > 0, fastOps > 0, ok ? "PASS" : "FAIL");
|
||||
if (ok) passed++;
|
||||
}
|
||||
|
||||
System.out.printf("%n%d/%d PASS%n", passed, total);
|
||||
if (passed != total) System.exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue