cleanup: remove duplicate hibernate-0007/quarkus-0003 patches; correct camel/rabbitmq UNDF stamps
This commit is contained in:
parent
919d3f2a57
commit
651aaa7e7b
8 changed files with 6 additions and 210 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# UNDF: UNDF-2026-000000360
|
||||
# UNDF: UNDF-2026-000000158
|
||||
# camel-0001 — O(R²) Route Startup Endpoint Clash Scan
|
||||
|
||||
**Severity:** HIGH
|
||||
|
|
|
|||
|
|
@ -1,110 +0,0 @@
|
|||
# UNDF: (pending)
|
||||
# hibernate-0007: InFlightMetadataCollectorImpl.buildRecursiveOrderedFkSecondPasses — O(2^D) diamond + O(N²) list scan
|
||||
|
||||
## CWE-407 — Algorithmic Complexity: O(2^D) diamond re-traversal + O(N) List.contains in FK ordering
|
||||
|
||||
| Field | Value |
|
||||
|--------------|-------|
|
||||
| ID | hibernate-0007 |
|
||||
| Severity | HIGH |
|
||||
| Ecosystem | hibernate |
|
||||
| Package | hibernate-core |
|
||||
| File | `hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java` |
|
||||
| Lines | 1835–1853 |
|
||||
| Complexity | O(2^D) on diamond FK dependency graphs; O(N) dedup guard |
|
||||
| Hot path | Called during schema bootstrap: `processSecondPasses()` → FK ordering phase |
|
||||
|
||||
## Defect
|
||||
|
||||
`buildRecursiveOrderedFkSecondPasses` recursively traverses the FK dependency graph
|
||||
to produce a topologically-ordered list of `FkSecondPass` operations. It uses `startTable`
|
||||
as a cycle guard (skips re-entering the starting table), but has no guard for diamond
|
||||
re-traversal of intermediate shared tables:
|
||||
|
||||
```java
|
||||
// InFlightMetadataCollectorImpl.java:1835-1853 (DEFECT)
|
||||
private void buildRecursiveOrderedFkSecondPasses(
|
||||
List<FkSecondPass> orderedFkSecondPasses,
|
||||
Map<String, Set<FkSecondPass>> isADependencyOf,
|
||||
String startTable,
|
||||
String currentTable) {
|
||||
final Set<FkSecondPass> dependencies = isADependencyOf.get( currentTable );
|
||||
if ( dependencies != null ) {
|
||||
for ( var fkSecondPass : dependencies ) {
|
||||
final String dependentTable = fkSecondPass.getValue().getTable()...render();
|
||||
if ( dependentTable.compareTo( startTable ) != 0 ) {
|
||||
buildRecursiveOrderedFkSecondPasses( // recurse — only guards startTable cycle,
|
||||
orderedFkSecondPasses, isADependencyOf, startTable, dependentTable ); // NOT diamond
|
||||
}
|
||||
if ( !orderedFkSecondPasses.contains( fkSecondPass ) ) { // O(N) List.contains!
|
||||
orderedFkSecondPasses.add( 0, fkSecondPass );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Two distinct defects:
|
||||
|
||||
1. **Diamond re-traversal O(2^D):** On a diamond FK dependency graph
|
||||
(T1 depends on T2 and T3; both T2 and T3 depend on T4), T4 is visited twice, 2^D times
|
||||
at depth D. The `startTable` guard only prevents cycles back to T1, not intermediate diamonds.
|
||||
|
||||
2. **O(N) List.contains dedup guard:** `orderedFkSecondPasses.contains(fkSecondPass)` is an
|
||||
O(N) scan of the already-ordered list. With N FK passes and diamond re-traversal,
|
||||
total cost: O(2^D × N). Even without diamonds, N passes each potentially visiting N
|
||||
already-ordered entries: O(N²).
|
||||
|
||||
## Fix
|
||||
|
||||
Add a `Set<String> visited` parameter to track globally-visited tables; replace
|
||||
`List.contains` with a `LinkedHashSet` for O(1) dedup:
|
||||
|
||||
```java
|
||||
// Call site — line 1804-1806
|
||||
final LinkedHashSet<FkSecondPass> orderedFkSecondPasses = new LinkedHashSet<>( fkSecondPassList.size() );
|
||||
for ( String tableName : isADependencyOf.keySet() ) {
|
||||
buildRecursiveOrderedFkSecondPasses( orderedFkSecondPasses, isADependencyOf, tableName, tableName, new HashSet<>() );
|
||||
}
|
||||
// process the ordered passes (LinkedHashSet preserves insertion order)
|
||||
for ( var sp : orderedFkSecondPasses ) {
|
||||
sp.doSecondPass( getEntityBindingMap() );
|
||||
}
|
||||
|
||||
// AFTER — O(N+E) total
|
||||
private void buildRecursiveOrderedFkSecondPasses(
|
||||
LinkedHashSet<FkSecondPass> orderedFkSecondPasses, // O(1) add/contains
|
||||
Map<String, Set<FkSecondPass>> isADependencyOf,
|
||||
String startTable,
|
||||
String currentTable,
|
||||
Set<String> visited) { // diamond guard
|
||||
if ( !visited.add( currentTable ) ) {
|
||||
return; // already traversed this table in this pass
|
||||
}
|
||||
final Set<FkSecondPass> dependencies = isADependencyOf.get( currentTable );
|
||||
if ( dependencies != null ) {
|
||||
for ( var fkSecondPass : dependencies ) {
|
||||
final String dependentTable = fkSecondPass.getValue().getTable().getQualifiedTableName().render();
|
||||
if ( dependentTable.compareTo( startTable ) != 0 ) {
|
||||
buildRecursiveOrderedFkSecondPasses( orderedFkSecondPasses, isADependencyOf,
|
||||
startTable, dependentTable, visited );
|
||||
}
|
||||
orderedFkSecondPasses.add( fkSecondPass ); // O(1) dedup via LinkedHashSet
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note: `LinkedHashSet` preserves insertion order (same semantics as `add(0, ...)` reversed)
|
||||
and provides O(1) `add`/`contains`. The `add(0, ...)` pattern builds the list in reverse
|
||||
topological order; `LinkedHashSet` with final reversal achieves the same.
|
||||
|
||||
## Speedup
|
||||
|
||||
| Diamond depth (D), N=100 passes | Before (visits) | After (visits) | Speedup |
|
||||
|---------------------------------|----------------|----------------|---------|
|
||||
| 5 | 3,100 | 100 | 31× |
|
||||
| 10 | 102,300 | 100 | 1,023× |
|
||||
| 15 | 3,276,700 | 100 | 32,767× |
|
||||
|
||||
Growth before: O(2^D × N). Growth after: O(N).
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
# UNDF: UNDF-2026-000000469
|
||||
# quarkus-0003: BeanDeployment.recursiveBuild — O(2^D) diamond re-traversal, no visited guard
|
||||
|
||||
## CWE-407 — Algorithmic Complexity: O(2^D) recursive diamond re-traversal in transitive interceptor binding resolution
|
||||
|
||||
| Field | Value |
|
||||
|--------------|-------|
|
||||
| ID | quarkus-0003 |
|
||||
| Severity | HIGH |
|
||||
| Ecosystem | quarkus |
|
||||
| Package | quarkus-arc-processor |
|
||||
| File | `independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java` |
|
||||
| Lines | 955–965 |
|
||||
| Complexity | O(2^D) on diamond interceptor binding hierarchies |
|
||||
| Hot path | Called at CDI container startup: `findTransitiveInterceptorBindings()` |
|
||||
|
||||
## Defect
|
||||
|
||||
`BeanDeployment.recursiveBuild(DotName name, Map<DotName, Set<AnnotationInstance>> transitiveBindingsMap)`
|
||||
computes the transitive closure of interceptor bindings without a visited guard:
|
||||
|
||||
```java
|
||||
// independent-projects/arc/processor/.../BeanDeployment.java:955-965 (DEFECT)
|
||||
private static Set<AnnotationInstance> recursiveBuild(DotName name,
|
||||
Map<DotName, Set<AnnotationInstance>> transitiveBindingsMap) {
|
||||
Set<AnnotationInstance> result = transitiveBindingsMap.get(name); // reference, not copy!
|
||||
for (AnnotationInstance instance : transitiveBindingsMap.get(name)) { // iterating same set
|
||||
if (transitiveBindingsMap.containsKey(instance.name())) {
|
||||
// recursively find — no visited guard
|
||||
result.addAll(recursiveBuild(instance.name(), transitiveBindingsMap)); // DEFECT 1: mutates result during iteration
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
Two distinct defects:
|
||||
|
||||
1. **Diamond re-traversal O(2^D):** No visited guard. On a diamond binding hierarchy
|
||||
(A→B, A→C, B→D, C→D), D is visited twice, 2^D times at depth D.
|
||||
|
||||
2. **Live-set mutation:** `result` is a reference to `transitiveBindingsMap.get(name)` — the
|
||||
same set being iterated. `result.addAll(recursiveBuild(...))` mutates it mid-iteration.
|
||||
Any newly-added element could cause `ConcurrentModificationException` on the next
|
||||
`instance` step, depending on Java's iterator implementation. This is undefined behavior.
|
||||
|
||||
## Fix
|
||||
|
||||
Add a `visited` set parameter; use a defensive copy of the initial bindings:
|
||||
|
||||
```java
|
||||
// AFTER — O(N+E) total, no CME risk
|
||||
private static Set<AnnotationInstance> recursiveBuild(DotName name,
|
||||
Map<DotName, Set<AnnotationInstance>> transitiveBindingsMap) {
|
||||
return recursiveBuild(name, transitiveBindingsMap, new HashSet<>());
|
||||
}
|
||||
|
||||
private static Set<AnnotationInstance> recursiveBuild(DotName name,
|
||||
Map<DotName, Set<AnnotationInstance>> transitiveBindingsMap,
|
||||
Set<DotName> visited) {
|
||||
if (!visited.add(name)) {
|
||||
return Collections.emptySet(); // diamond guard: already computed for this name
|
||||
}
|
||||
Set<AnnotationInstance> initial = transitiveBindingsMap.get(name);
|
||||
Set<AnnotationInstance> result = new HashSet<>(initial); // defensive copy — safe to mutate
|
||||
for (AnnotationInstance instance : initial) {
|
||||
if (transitiveBindingsMap.containsKey(instance.name())) {
|
||||
result.addAll(recursiveBuild(instance.name(), transitiveBindingsMap, visited));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
Also update the call site to store back the result:
|
||||
```java
|
||||
// findTransitiveInterceptorBindings — line 949-951
|
||||
for (DotName name : result.keySet()) {
|
||||
result.put(name, recursiveBuild(name, result));
|
||||
}
|
||||
```
|
||||
The call site is already correct — it stores the returned set back. The fix makes the returned
|
||||
set a fresh copy rather than a mutation of the shared map entry.
|
||||
|
||||
## Speedup
|
||||
|
||||
| Diamond depth (D) | Before (visits) | After (visits) | Speedup |
|
||||
|------------------|----------------|----------------|---------|
|
||||
| 5 | 31 | 5 | 6× |
|
||||
| 10 | 1,023 | 10 | 102× |
|
||||
| 15 | 32,767 | 15 | 2,184× |
|
||||
| 20 | 1,048,575 | 20 | 52,428× |
|
||||
|
||||
Growth before: O(2^D). Growth after: O(D).
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# UNDF: UNDF-2026-000000237
|
||||
# UNDF: UNDF-2026-000000239
|
||||
--- a/deps/rabbit/src/rabbit_classic_queue.erl
|
||||
+++ b/deps/rabbit/src/rabbit_classic_queue.erl
|
||||
@@ -9,7 +9,7 @@
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# UNDF: UNDF-2026-000000238
|
||||
# UNDF: UNDF-2026-000000240
|
||||
--- a/deps/rabbit/src/rabbit_stream_sac_coordinator.erl
|
||||
+++ b/deps/rabbit/src/rabbit_stream_sac_coordinator.erl
|
||||
@@ -200,15 +200,18 @@ filter_dead_pids(Pids) ->
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# UNDF: UNDF-2026-000000239
|
||||
# UNDF: UNDF-2026-000000360
|
||||
--- a/deps/rabbit/src/rabbit_amqqueue.erl
|
||||
+++ b/deps/rabbit/src/rabbit_amqqueue.erl
|
||||
@@ -902,12 +902,14 @@ check_declare_arguments(QueueName, Args0, DefaultQueueType) ->
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# UNDF: UNDF-2026-000000240
|
||||
# UNDF: UNDF-2026-000000387
|
||||
--- a/deps/rabbit/src/rabbit_amqqueue.erl
|
||||
+++ b/deps/rabbit/src/rabbit_amqqueue.erl
|
||||
@@ -932,11 +932,12 @@ check_arguments_key(QueueName, QueueType, Args, InvalidArgs) ->
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# UNDF: UNDF-2026-000000520
|
||||
# UNDF: UNDF-2026-000000473
|
||||
# rmq-0005: rabbit_mgmt_wm_definitions export_binding O(B×Q) → O(B+Q)
|
||||
|
||||
## Location
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue