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
|
# camel-0001 — O(R²) Route Startup Endpoint Clash Scan
|
||||||
|
|
||||||
**Severity:** HIGH
|
**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
|
--- a/deps/rabbit/src/rabbit_classic_queue.erl
|
||||||
+++ b/deps/rabbit/src/rabbit_classic_queue.erl
|
+++ b/deps/rabbit/src/rabbit_classic_queue.erl
|
||||||
@@ -9,7 +9,7 @@
|
@@ -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
|
--- a/deps/rabbit/src/rabbit_stream_sac_coordinator.erl
|
||||||
+++ b/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) ->
|
@@ -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
|
--- a/deps/rabbit/src/rabbit_amqqueue.erl
|
||||||
+++ b/deps/rabbit/src/rabbit_amqqueue.erl
|
+++ b/deps/rabbit/src/rabbit_amqqueue.erl
|
||||||
@@ -902,12 +902,14 @@ check_declare_arguments(QueueName, Args0, DefaultQueueType) ->
|
@@ -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
|
--- a/deps/rabbit/src/rabbit_amqqueue.erl
|
||||||
+++ b/deps/rabbit/src/rabbit_amqqueue.erl
|
+++ b/deps/rabbit/src/rabbit_amqqueue.erl
|
||||||
@@ -932,11 +932,12 @@ check_arguments_key(QueueName, QueueType, Args, InvalidArgs) ->
|
@@ -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)
|
# rmq-0005: rabbit_mgmt_wm_definitions export_binding O(B×Q) → O(B+Q)
|
||||||
|
|
||||||
## Location
|
## Location
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue