wave17: postgres-0001/asterisk-0001/haproxy-0001/nginx-0001; postfix+bevy CLEAN
postgres-0001: pg_inherits.c typeInheritsFrom() BFS visited List → HTAB O(1) asterisk-0001: app_queue.c interface_exists() ao2_iterator walk → ao2_find O(1) haproxy-0001: http_ana.c cookie-server scan linked-list → eb-tree index O(log S) nginx-0001: ngx_http_link_multi_headers() O(H²) double-scan → O(H) hash pass postfix: CLEAN (htable throughout; two marginal LOW admin-bounded candidates) bevy: CLEAN (FixedBitSet/HashSet throughout; only hardware-bounded marginals)
This commit is contained in:
parent
da8b4a41d6
commit
ff6292d067
10 changed files with 627 additions and 252 deletions
|
|
@ -0,0 +1,72 @@
|
|||
--- a/src/backend/catalog/pg_inherits.c
|
||||
+++ b/src/backend/catalog/pg_inherits.c
|
||||
@@ -406,12 +406,16 @@ bool
|
||||
typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
|
||||
{
|
||||
bool result = false;
|
||||
Oid subclassRelid;
|
||||
Oid superclassRelid;
|
||||
Relation inhrel;
|
||||
- List *visited,
|
||||
- *queue;
|
||||
+ HTAB *visited_set; /* O(1) OID lookup; replaces O(V) list_member_oid */
|
||||
+ HASHCTL ctl;
|
||||
+ List *queue;
|
||||
ListCell *queue_item;
|
||||
|
||||
/* We need to work with the associated relation OIDs */
|
||||
subclassRelid = typeOrDomainTypeRelid(subclassTypeId);
|
||||
if (subclassRelid == InvalidOid)
|
||||
@@ -428,7 +432,14 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
|
||||
queue = list_make1_oid(subclassRelid);
|
||||
- visited = NIL;
|
||||
+
|
||||
+ ctl.keysize = sizeof(Oid);
|
||||
+ ctl.entrysize = sizeof(Oid);
|
||||
+ ctl.hcxt = CurrentMemoryContext;
|
||||
+ visited_set = hash_create("typeInheritsFrom visited set",
|
||||
+ 32,
|
||||
+ &ctl,
|
||||
+ HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
|
||||
|
||||
inhrel = table_open(InheritsRelationId, AccessShareLock);
|
||||
|
||||
@@ -443,11 +454,12 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
|
||||
foreach(queue_item, queue)
|
||||
{
|
||||
Oid this_relid = lfirst_oid(queue_item);
|
||||
ScanKeyData skey;
|
||||
SysScanDesc inhscan;
|
||||
HeapTuple inhtup;
|
||||
+ bool found;
|
||||
|
||||
/*
|
||||
* If we've seen this relid already, skip it. This avoids extra work
|
||||
* in multiple-inheritance scenarios, and also protects us from an
|
||||
* infinite loop in case there is a cycle in pg_inherits (though
|
||||
* theoretically that shouldn't happen).
|
||||
*/
|
||||
- if (list_member_oid(visited, this_relid))
|
||||
+ hash_search(visited_set, &this_relid, HASH_ENTER, &found);
|
||||
+ if (found)
|
||||
continue;
|
||||
|
||||
- /*
|
||||
- * Okay, this is a not-yet-seen relid. Add it to the list of
|
||||
- * already-visited OIDs, then find all the types this relid inherits
|
||||
- * from and add them to the queue.
|
||||
- */
|
||||
- visited = lappend_oid(visited, this_relid);
|
||||
-
|
||||
ScanKeyInit(&skey,
|
||||
Anum_pg_inherits_inhrelid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
@@ -493,7 +497,7 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
|
||||
/* clean up ... */
|
||||
table_close(inhrel, AccessShareLock);
|
||||
|
||||
- list_free(visited);
|
||||
+ hash_destroy(visited_set);
|
||||
list_free(queue);
|
||||
|
||||
return result;
|
||||
113
defects/postgres/unit/PostgresTest.java
Normal file
113
defects/postgres/unit/PostgresTest.java
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 unit test for PostgreSQL pg_inherits.c defect.
|
||||
*
|
||||
* postgres-0001: src/backend/catalog/pg_inherits.c typeInheritsFrom()
|
||||
* BFS over pg_inherits using List *visited + list_member_oid() — O(V) per node,
|
||||
* O(V²) total for a deep/wide hierarchy.
|
||||
* Fix: replace List *visited with HTAB *visited_set (same pattern as
|
||||
* find_all_inheritors in the same file) for O(1) per-node visited check.
|
||||
*/
|
||||
public class PostgresTest {
|
||||
|
||||
// Simulate defect: List visited + linear scan
|
||||
static boolean typeInheritsFrom_list(int[][] parentEdges, int subclass, int superclass) {
|
||||
// parentEdges[i] = {child_oid, parent_oid}
|
||||
// BFS from subclass upward; visited is a list (O(V) scan per entry)
|
||||
List<Integer> queue = new ArrayList<>();
|
||||
List<Integer> visited = new ArrayList<>();
|
||||
queue.add(subclass);
|
||||
|
||||
int head = 0;
|
||||
while (head < queue.size()) {
|
||||
int current = queue.get(head++);
|
||||
boolean alreadySeen = false;
|
||||
for (int v : visited) { // O(V) — defect
|
||||
if (v == current) { alreadySeen = true; break; }
|
||||
}
|
||||
if (alreadySeen) continue;
|
||||
visited.add(current);
|
||||
|
||||
for (int[] edge : parentEdges) {
|
||||
if (edge[0] == current) {
|
||||
int parent = edge[1];
|
||||
if (parent == superclass) return true;
|
||||
queue.add(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Simulate fix: HashSet visited
|
||||
static boolean typeInheritsFrom_htab(int[][] parentEdges, int subclass, int superclass) {
|
||||
List<Integer> queue = new ArrayList<>();
|
||||
Set<Integer> visited = new HashSet<>(); // O(1) lookup
|
||||
queue.add(subclass);
|
||||
|
||||
int head = 0;
|
||||
while (head < queue.size()) {
|
||||
int current = queue.get(head++);
|
||||
if (!visited.add(current)) continue; // O(1)
|
||||
|
||||
for (int[] edge : parentEdges) {
|
||||
if (edge[0] == current) {
|
||||
int parent = edge[1];
|
||||
if (parent == superclass) return true;
|
||||
queue.add(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void testPostgres0001() throws Exception {
|
||||
// Build a diamond-inheritance graph: V types in a chain with cross-links
|
||||
// Use the negative case (not found) — forces full BFS traversal of all V nodes,
|
||||
// maximising the visited-list size reached during each member check.
|
||||
int V = 800;
|
||||
// All-to-all fan-out: node i has edges to i+1..i+10 (wide BFS tree)
|
||||
List<int[]> edges = new ArrayList<>();
|
||||
for (int i = 0; i < V; i++) {
|
||||
for (int k = 1; k <= 10 && i + k < V; k++) {
|
||||
edges.add(new int[]{i, i + k});
|
||||
}
|
||||
}
|
||||
int[][] parentEdges = edges.toArray(new int[0][]);
|
||||
|
||||
int subclass = 0;
|
||||
int superclass = V - 1; // reachable (positive case)
|
||||
int missing = 999999; // not reachable (negative case — full traversal)
|
||||
|
||||
// correctness
|
||||
boolean r1 = typeInheritsFrom_list(parentEdges, subclass, superclass);
|
||||
boolean r2 = typeInheritsFrom_htab(parentEdges, subclass, superclass);
|
||||
assert r1 == r2 : "list and htab must agree (positive): " + r1 + " vs " + r2;
|
||||
|
||||
boolean n1 = typeInheritsFrom_list(parentEdges, subclass, missing);
|
||||
boolean n2 = typeInheritsFrom_htab(parentEdges, subclass, missing);
|
||||
assert n1 == n2 && !n1 : "negative case must agree";
|
||||
|
||||
// performance on negative case: forces complete traversal, visited grows to V
|
||||
int REPS = 100;
|
||||
long t0 = System.nanoTime();
|
||||
for (int r = 0; r < REPS; r++) typeInheritsFrom_list(parentEdges, subclass, missing);
|
||||
long tList = System.nanoTime() - t0;
|
||||
|
||||
t0 = System.nanoTime();
|
||||
for (int r = 0; r < REPS; r++) typeInheritsFrom_htab(parentEdges, subclass, missing);
|
||||
long tHash = System.nanoTime() - t0;
|
||||
|
||||
double ratio = (double) tList / tHash;
|
||||
System.out.printf("postgres-0001: list=%.3fs htab=%.3fs ratio=%.1f×%n",
|
||||
tList / 1e9, tHash / 1e9, ratio);
|
||||
assert ratio > 1.2 : "Expected >1.2× speedup, got " + ratio;
|
||||
System.out.println("PASS postgres-0001");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testPostgres0001();
|
||||
System.out.println("ALL PASS");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue