game engines/web frameworks: 27 CWE-407 defects + 3 CLEAN; 194 sites, 78 ecosystems
This commit is contained in:
parent
547a9f5738
commit
4d3fcc8e73
76 changed files with 6216 additions and 17 deletions
170
defects/ogre/unit/OGRETest.java
Normal file
170
defects/ogre/unit/OGRETest.java
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* OGRETest — Java analogs of three OGRE CWE-407 defects.
|
||||
*
|
||||
* Defect 1 (ogre-0001): Node::~Node — std::find on vector of queued-update nodes.
|
||||
* Slow: ArrayList.remove(Object) — O(N) scan per node destroyed.
|
||||
* Fast: LinkedHashSet.remove(Object) — O(1) per node destroyed.
|
||||
*
|
||||
* Defect 2 (ogre-0002): ResourceGroupManager::_notifyAllResourcesRemoved — std::find
|
||||
* in nested loop erasing resources from a list.
|
||||
* Slow: ArrayList.remove(Object) inside an erase loop — O(N²).
|
||||
* Fast: Build HashSet of to-remove pointers, single-pass removeIf — O(N).
|
||||
*
|
||||
* Defect 3 (ogre-0003): RibbonTrail::clearChain — std::find on parallel index vector
|
||||
* to reverse-map chain-index → node.
|
||||
* Slow: ArrayList.indexOf(chainIndex) — O(N).
|
||||
* Fast: HashMap<Integer,Object> reverse map — O(1).
|
||||
*/
|
||||
public class OGRETest {
|
||||
|
||||
static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) {
|
||||
// warmup
|
||||
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 ratio = fOps > 0 ? (double) sOps / fOps : 0;
|
||||
System.out.printf(" %-56s slow:%5dms (%,d ops) fast:%5dms (%,d ops) speedup:%.0fx%n",
|
||||
label, sMs, sOps, fMs, fOps, ratio);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// ogre-0001: Node queued-update removal during bulk destruction
|
||||
// -----------------------------------------------------------------------
|
||||
static void benchNodeQueuedUpdates(int N) {
|
||||
// SLOW: vector — O(N) scan per node destruction
|
||||
Runnable slow = () -> {
|
||||
List<Object> queue = new ArrayList<>(N);
|
||||
Object[] nodes = new Object[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
nodes[i] = new Object();
|
||||
queue.add(nodes[i]);
|
||||
}
|
||||
// simulate N node destructions: each does std::find + erase
|
||||
for (int i = 0; i < N; i++) {
|
||||
queue.remove(nodes[i]); // O(N) scan
|
||||
}
|
||||
};
|
||||
|
||||
// FAST: unordered_set — O(1) erase per node destruction
|
||||
Runnable fast = () -> {
|
||||
Set<Object> queue = new LinkedHashSet<>(N * 2);
|
||||
Object[] nodes = new Object[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
nodes[i] = new Object();
|
||||
queue.add(nodes[i]);
|
||||
}
|
||||
for (int i = 0; i < N; i++) {
|
||||
queue.remove(nodes[i]); // O(1) hash remove
|
||||
}
|
||||
};
|
||||
|
||||
long sOps = (long) N * N / 2; // average scan length N/2 × N destructions
|
||||
long fOps = N;
|
||||
bench(String.format("ogre-0001 Node::~Node queued-update scan N=%d", N),
|
||||
slow, fast, sOps, fOps);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// ogre-0002: ResourceGroupManager notify-removed — nested find+erase
|
||||
// -----------------------------------------------------------------------
|
||||
static void benchResourceGroupRemove(int R) {
|
||||
// SLOW: std::find on list for each item in arDel — O(R²)
|
||||
Runnable slow = () -> {
|
||||
List<Object> resourceList = new ArrayList<>(R);
|
||||
for (int i = 0; i < R; i++) resourceList.add(new Object());
|
||||
List<Object> arDel = new ArrayList<>(resourceList); // remove all
|
||||
|
||||
for (Object item : arDel) {
|
||||
resourceList.remove(item); // O(R) scan each time
|
||||
}
|
||||
};
|
||||
|
||||
// FAST: build HashSet, single-pass removeIf — O(R)
|
||||
Runnable fast = () -> {
|
||||
List<Object> resourceList = new ArrayList<>(R);
|
||||
for (int i = 0; i < R; i++) resourceList.add(new Object());
|
||||
List<Object> arDel = new ArrayList<>(resourceList);
|
||||
|
||||
Set<Object> toRemove = new HashSet<>(arDel);
|
||||
resourceList.removeIf(toRemove::contains); // O(R) single pass
|
||||
};
|
||||
|
||||
long sOps = (long) R * R;
|
||||
long fOps = R;
|
||||
bench(String.format("ogre-0002 ResourceGroupManager::_notifyRemoved R=%d", R),
|
||||
slow, fast, sOps, fOps);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// ogre-0003: RibbonTrail::clearChain — parallel-vector reverse lookup
|
||||
// -----------------------------------------------------------------------
|
||||
static void benchRibbonTrailClearChain(int K, int clears) {
|
||||
Object[] nodes = new Object[K];
|
||||
for (int i = 0; i < K; i++) nodes[i] = new Object();
|
||||
|
||||
// SLOW: parallel arrays, indexOf for reverse lookup
|
||||
Runnable slow = () -> {
|
||||
List<Object> nodeList = new ArrayList<>(Arrays.asList(nodes));
|
||||
List<Integer> chainSegments = new ArrayList<>();
|
||||
for (int i = 0; i < K; i++) chainSegments.add(i);
|
||||
|
||||
long dummy = 0;
|
||||
for (int c = 0; c < clears; c++) {
|
||||
int chainIndex = c % K;
|
||||
// std::find on mNodeToChainSegment — O(K)
|
||||
int pos = chainSegments.indexOf(chainIndex);
|
||||
if (pos >= 0) dummy += pos;
|
||||
}
|
||||
if (dummy < 0) System.out.println("never");
|
||||
};
|
||||
|
||||
// FAST: HashMap for reverse lookup — O(1) per clear
|
||||
Runnable fast = () -> {
|
||||
Map<Integer, Object> chainToNode = new HashMap<>(K * 2);
|
||||
for (int i = 0; i < K; i++) chainToNode.put(i, nodes[i]);
|
||||
|
||||
long dummy = 0;
|
||||
for (int c = 0; c < clears; c++) {
|
||||
int chainIndex = c % K;
|
||||
// HashMap.get — O(1)
|
||||
Object n = chainToNode.get(chainIndex);
|
||||
if (n != null) dummy++;
|
||||
}
|
||||
if (dummy < 0) System.out.println("never");
|
||||
};
|
||||
|
||||
long sOps = (long) clears * K;
|
||||
long fOps = clears;
|
||||
bench(String.format("ogre-0003 RibbonTrail::clearChain K=%d clears=%d", K, clears),
|
||||
slow, fast, sOps, fOps);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("OGRE CWE-407 defect benchmarks");
|
||||
System.out.println("=".repeat(100));
|
||||
|
||||
System.out.println("\n[ogre-0001] Node::~Node — msQueuedUpdates linear scan");
|
||||
benchNodeQueuedUpdates(500);
|
||||
benchNodeQueuedUpdates(2_000);
|
||||
benchNodeQueuedUpdates(10_000);
|
||||
|
||||
System.out.println("\n[ogre-0002] ResourceGroupManager::_notifyAllResourcesRemoved");
|
||||
benchResourceGroupRemove(500);
|
||||
benchResourceGroupRemove(2_000);
|
||||
benchResourceGroupRemove(10_000);
|
||||
|
||||
System.out.println("\n[ogre-0003] RibbonTrail::clearChain — parallel-vector reverse lookup");
|
||||
benchRibbonTrailClearChain(50, 100_000);
|
||||
benchRibbonTrailClearChain(200, 100_000);
|
||||
benchRibbonTrailClearChain(1_000, 100_000);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue