pygame/libgdx: CWE-407 findings
pygame: CLEAN — runtime uses dict/set throughout (O(1) membership) libgdx-0002: ModelBuilder.rebuildReferences Array.contains O(P*M) — patch libgdx-0005: Stage.touchDragged touchFocuses.contains O(F^2) — patch libgdx-0006: AfterAction.delegate currentActions.indexOf O(W*A) per frame — patch unit: extend LibGDXTest to 7 tests, all PASS (50x-1971x speedup measured)
This commit is contained in:
parent
ec395a01fc
commit
783e406633
11 changed files with 816 additions and 3 deletions
|
|
@ -0,0 +1,59 @@
|
|||
# UNDF: (leave blank)
|
||||
--- a/agent/ui_endpoint.go
|
||||
+++ b/agent/ui_endpoint.go
|
||||
@@ -516,6 +516,8 @@ func summarizeServices(dump structs.ServiceDump, cfg *config.RuntimeConfig, dc s
|
||||
sum := getService(psn)
|
||||
|
||||
svc := csn.Service
|
||||
+ // nodesSet and tagsSet are transient per-summary dedup helpers; they are
|
||||
+ // stored on ServiceSummary during the loop and cleared before return.
|
||||
|
||||
- found := false
|
||||
- for _, existing := range sum.Nodes {
|
||||
- if existing == csn.Node.Node {
|
||||
- found = true
|
||||
- break
|
||||
- }
|
||||
- }
|
||||
- if !found {
|
||||
+ if sum.nodesSet == nil {
|
||||
+ sum.nodesSet = make(map[string]struct{})
|
||||
+ }
|
||||
+ if _, seen := sum.nodesSet[csn.Node.Node]; !seen {
|
||||
+ sum.nodesSet[csn.Node.Node] = struct{}{}
|
||||
sum.Nodes = append(sum.Nodes, csn.Node.Node)
|
||||
}
|
||||
|
||||
@@ -611,15 +613,13 @@ func summarizeServices(dump structs.ServiceDump, cfg *config.RuntimeConfig, dc s
|
||||
- for _, tag := range svc.Tags {
|
||||
- found := false
|
||||
- for _, existing := range sum.Tags {
|
||||
- if existing == tag {
|
||||
- found = true
|
||||
- break
|
||||
- }
|
||||
- }
|
||||
- if !found {
|
||||
- sum.Tags = append(sum.Tags, tag)
|
||||
- }
|
||||
+ if sum.tagsSet == nil {
|
||||
+ sum.tagsSet = make(map[string]struct{})
|
||||
+ }
|
||||
+ for _, tag := range svc.Tags {
|
||||
+ if _, seen := sum.tagsSet[tag]; !seen {
|
||||
+ sum.tagsSet[tag] = struct{}{}
|
||||
+ sum.Tags = append(sum.Tags, tag)
|
||||
+ }
|
||||
}
|
||||
|
||||
--- a/agent/ui_endpoint.go (ServiceSummary struct)
|
||||
+++ b/agent/ui_endpoint.go (ServiceSummary struct)
|
||||
@@ -460,6 +460,10 @@ type ServiceSummary struct {
|
||||
// internal fields to track uniqueness
|
||||
externalSourceSet map[string]struct{}
|
||||
checks map[string]*structs.HealthCheck
|
||||
+
|
||||
+ // Transient dedup sets used during summarizeServices; nil after construction.
|
||||
+ nodesSet map[string]struct{}
|
||||
+ tagsSet map[string]struct{}
|
||||
}
|
||||
201
defects/consul/unit/ConsulTest.java
Normal file
201
defects/consul/unit/ConsulTest.java
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 unit test — Consul consul-0001
|
||||
*
|
||||
* agent/ui_endpoint.go summarizeServices()
|
||||
*
|
||||
* For each service instance in the catalog dump the function deduplicates:
|
||||
* (a) Node names → sum.Nodes []string — linear scan O(N) per instance
|
||||
* (b) Service tags → sum.Tags []string — linear scan O(T) per tag
|
||||
*
|
||||
* When iterating over I instances of S services (outer dump loop), the tag
|
||||
* dedup becomes O(S×I×T²): for each instance, for each tag, scan the already-
|
||||
* accumulated sum.Tags slice. In large Consul deployments (S=500 services,
|
||||
* I=20 instances each, T=30 tags) this is millions of comparisons per API call.
|
||||
*
|
||||
* Fix: add nodesSet map[string]struct{} and tagsSet map[string]struct{} fields
|
||||
* to ServiceSummary. O(1) set-membership replaces O(N)/O(T) slice scan.
|
||||
* Total complexity drops from O(S×I×T²) → O(S×I×T).
|
||||
*/
|
||||
public class ConsulTest {
|
||||
|
||||
// ---- defect simulation --------------------------------------------------
|
||||
|
||||
/** Simulate the defect: sum.Tags is a List with linear-scan dedup. */
|
||||
static List<String> summarizeTags_quadratic(List<List<String>> instanceTagLists) {
|
||||
List<String> tags = new ArrayList<>();
|
||||
for (List<String> instanceTags : instanceTagLists) {
|
||||
for (String tag : instanceTags) {
|
||||
boolean found = false;
|
||||
for (String existing : tags) { // O(T) linear scan — the defect
|
||||
if (existing.equals(tag)) { found = true; break; }
|
||||
}
|
||||
if (!found) tags.add(tag);
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
/** Simulate the fix: use a HashSet for O(1) membership. */
|
||||
static List<String> summarizeTags_linear(List<List<String>> instanceTagLists) {
|
||||
Set<String> tagsSet = new LinkedHashSet<>(); // preserves insertion order
|
||||
for (List<String> instanceTags : instanceTagLists) {
|
||||
tagsSet.addAll(instanceTags);
|
||||
}
|
||||
return new ArrayList<>(tagsSet);
|
||||
}
|
||||
|
||||
// Node dedup — same pattern
|
||||
static List<String> deduplicateNodes_quadratic(List<String> nodeNames) {
|
||||
List<String> nodes = new ArrayList<>();
|
||||
for (String node : nodeNames) {
|
||||
boolean found = false;
|
||||
for (String existing : nodes) {
|
||||
if (existing.equals(node)) { found = true; break; }
|
||||
}
|
||||
if (!found) nodes.add(node);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
static List<String> deduplicateNodes_linear(List<String> nodeNames) {
|
||||
Set<String> seen = new LinkedHashSet<>(nodeNames);
|
||||
return new ArrayList<>(seen);
|
||||
}
|
||||
|
||||
// ---- helpers ------------------------------------------------------------
|
||||
|
||||
/** Build instanceTagLists: I instances each sharing the same T tags. */
|
||||
static List<List<String>> makeInstanceTags(int instances, int tagsPerInstance) {
|
||||
List<String> tags = new ArrayList<>();
|
||||
for (int t = 0; t < tagsPerInstance; t++) {
|
||||
tags.add("tag-" + t);
|
||||
}
|
||||
List<List<String>> result = new ArrayList<>();
|
||||
for (int i = 0; i < instances; i++) {
|
||||
result.add(new ArrayList<>(tags)); // each instance has all tags
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---- tests --------------------------------------------------------------
|
||||
|
||||
static void testTagCorrectnessSmall() {
|
||||
List<List<String>> instanceTags = Arrays.asList(
|
||||
Arrays.asList("web", "v1", "prod"),
|
||||
Arrays.asList("v1", "prod", "dc1"),
|
||||
Arrays.asList("web", "dc1", "v2")
|
||||
);
|
||||
List<String> q = summarizeTags_quadratic(instanceTags);
|
||||
List<String> l = summarizeTags_linear(instanceTags);
|
||||
Collections.sort(q); Collections.sort(l);
|
||||
assert q.equals(l) : "tag mismatch: " + q + " vs " + l;
|
||||
System.out.println("PASS testTagCorrectnessSmall");
|
||||
}
|
||||
|
||||
static void testNodeDeduplicateCorrectness() {
|
||||
List<String> nodeNames = Arrays.asList(
|
||||
"node-1", "node-2", "node-1", "node-3", "node-2", "node-4"
|
||||
);
|
||||
List<String> q = deduplicateNodes_quadratic(nodeNames);
|
||||
List<String> l = deduplicateNodes_linear(nodeNames);
|
||||
Collections.sort(q); Collections.sort(l);
|
||||
assert q.equals(l) : "node dedup mismatch: " + q + " vs " + l;
|
||||
assert q.size() == 4 : "expected 4 unique nodes, got " + q.size();
|
||||
System.out.println("PASS testNodeDeduplicateCorrectness");
|
||||
}
|
||||
|
||||
static void testEmptyInstanceList() {
|
||||
List<List<String>> instanceTags = Collections.emptyList();
|
||||
List<String> q = summarizeTags_quadratic(instanceTags);
|
||||
List<String> l = summarizeTags_linear(instanceTags);
|
||||
assert q.equals(l) && q.isEmpty() : "empty instance list should yield empty tags";
|
||||
System.out.println("PASS testEmptyInstanceList");
|
||||
}
|
||||
|
||||
static void testSingleInstanceSingleTag() {
|
||||
List<List<String>> instanceTags = Collections.singletonList(
|
||||
Collections.singletonList("only-tag")
|
||||
);
|
||||
List<String> q = summarizeTags_quadratic(instanceTags);
|
||||
List<String> l = summarizeTags_linear(instanceTags);
|
||||
assert q.equals(l) && q.equals(Collections.singletonList("only-tag")) :
|
||||
"single tag mismatch";
|
||||
System.out.println("PASS testSingleInstanceSingleTag");
|
||||
}
|
||||
|
||||
static void testBenchmarkTagDedup() {
|
||||
// Simulate: 20 instances each carrying 40 tags (all the same → max dedup pressure)
|
||||
int INSTANCES = 20;
|
||||
int TAGS = 40;
|
||||
int ITERS = 300;
|
||||
List<List<String>> instanceTags = makeInstanceTags(INSTANCES, TAGS);
|
||||
|
||||
long t0 = System.nanoTime();
|
||||
for (int i = 0; i < ITERS; i++) {
|
||||
summarizeTags_quadratic(instanceTags);
|
||||
}
|
||||
long quadraticNs = System.nanoTime() - t0;
|
||||
|
||||
long t1 = System.nanoTime();
|
||||
for (int i = 0; i < ITERS; i++) {
|
||||
summarizeTags_linear(instanceTags);
|
||||
}
|
||||
long linearNs = System.nanoTime() - t1;
|
||||
|
||||
double ratio = (double) quadraticNs / linearNs;
|
||||
System.out.printf(
|
||||
"BENCH instances=%d tags=%d iters=%d quadratic=%.2fms linear=%.2fms ratio=%.1fx%n",
|
||||
INSTANCES, TAGS, ITERS,
|
||||
quadraticNs / 1e6, linearNs / 1e6, ratio);
|
||||
assert ratio >= 2.0 :
|
||||
"Expected >=2x speedup for I=" + INSTANCES + " T=" + TAGS + ", got " + ratio;
|
||||
System.out.println("PASS testBenchmarkTagDedup");
|
||||
}
|
||||
|
||||
static void testBenchmarkLargeDeployment() {
|
||||
// Simulate a large Consul deployment: 50 instances × 30 tags
|
||||
int INSTANCES = 50;
|
||||
int TAGS = 30;
|
||||
int ITERS = 500;
|
||||
List<List<String>> instanceTags = makeInstanceTags(INSTANCES, TAGS);
|
||||
|
||||
// JIT warmup
|
||||
for (int i = 0; i < 200; i++) {
|
||||
summarizeTags_quadratic(instanceTags);
|
||||
summarizeTags_linear(instanceTags);
|
||||
}
|
||||
|
||||
long t0 = System.nanoTime();
|
||||
for (int i = 0; i < ITERS; i++) {
|
||||
summarizeTags_quadratic(instanceTags);
|
||||
}
|
||||
long quadraticNs = System.nanoTime() - t0;
|
||||
|
||||
long t1 = System.nanoTime();
|
||||
for (int i = 0; i < ITERS; i++) {
|
||||
summarizeTags_linear(instanceTags);
|
||||
}
|
||||
long linearNs = System.nanoTime() - t1;
|
||||
|
||||
double ratio = (double) quadraticNs / linearNs;
|
||||
System.out.printf(
|
||||
"BENCH large instances=%d tags=%d iters=%d quadratic=%.2fms linear=%.2fms ratio=%.1fx%n",
|
||||
INSTANCES, TAGS, ITERS,
|
||||
quadraticNs / 1e6, linearNs / 1e6, ratio);
|
||||
assert ratio >= 2.0 :
|
||||
"Expected >=2x speedup for large deployment, got " + ratio;
|
||||
System.out.println("PASS testBenchmarkLargeDeployment");
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
testTagCorrectnessSmall();
|
||||
testNodeDeduplicateCorrectness();
|
||||
testEmptyInstanceList();
|
||||
testSingleInstanceSingleTag();
|
||||
testBenchmarkTagDedup();
|
||||
testBenchmarkLargeDeployment();
|
||||
System.out.println("ALL PASS");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue