Skip to content

ARTEMIS-6199 Fix race in WildcardAddressManager - #6637

Merged
jbertram merged 1 commit into
apache:mainfrom
jbertram:ARTEMIS-6199
Aug 24, 2026
Merged

ARTEMIS-6199 Fix race in WildcardAddressManager#6637
jbertram merged 1 commit into
apache:mainfrom
jbertram:ARTEMIS-6199

Conversation

@jbertram

Copy link
Copy Markdown
Contributor

When a message is routed, the Bindings for the address is fetched from the address manager. If the Bindings doesn't already exist then it is created. Creating the bindings involves traversing the address tree map to find all matching wildcard addresses. When a matching address is found its bindings are copied.

Traversing the address tree map is performed without any kind of synchronization. Therefore, a concurrent operation to remove a binding can modify a wildcard address's Bindings mid-copy. This produces a Bindings that is missing the binding being concurrently removed. The removeBinding visitor then walks matching addresses to remove the binding from each, but fails with IllegalStateException on the address where the binding was never copied. This can also leak entires in addressMap & mappings eventually leading to OOME, since the exception aborts the visitor traversal and skips cleanup of remaining addresses.

  • Add addressMapLock to synchronize the lazy-creation path in getBindingsForRoutingAddress with addBinding, removeBinding, removeAddressInfo, and clear. The common path (cache hit) does not acquire the lock.
  • Catch IllegalStateException in the removeBinding visitor as defense-in-depth so that a missing binding does not abort the traversal and leak remaining entries.
  • Add tests to reproduce the race: a deterministic test that simulates the inconsistent state and verifies the visitor handles the missing binding, and a concurrent stress test that exercises getBindingsForRoutingAddress against wildcard binding add/remove.

@jbertram

Copy link
Copy Markdown
Contributor Author

FYI - The full test-suite is green on this.

When a message is routed, the Bindings for the address is fetched from
the address manager. If the Bindings doesn't already exist then it is
created. Creating the bindings involves traversing the address tree map
to find all matching wildcard addresses. When a matching address is
found its bindings are copied.

Traversing the address tree map is performed without any kind of
synchronization. Therefore, a concurrent operation to remove a binding
can modify a wildcard address's Bindings mid-copy. This produces a
Bindings that is missing the binding being concurrently removed. The
removeBinding visitor then walks matching addresses to remove the
binding from each, but fails with IllegalStateException on the address
where the binding was never copied. This can also leak entires in
addressMap & mappings eventually leading to OOME, since the exception
aborts the visitor traversal and skips cleanup of remaining addresses.

- Add addressMapLock to synchronize the lazy-creation path in
  getBindingsForRoutingAddress with addBinding, removeBinding,
  removeAddressInfo, and clear. The common path (cache hit) does not
  acquire the lock.
- Catch IllegalStateException in the removeBinding visitor as
  defense-in-depth so that a missing binding does not abort the
  traversal and leak remaining entries.
- Add tests to reproduce the race: a deterministic test that simulates
  the inconsistent state and verifies the visitor handles the missing
  binding, and a concurrent stress test that exercises
  getBindingsForRoutingAddress against wildcard binding add/remove.

Co-Authored-By: Claude <noreply@anthropic.com>
@clebertsuconic

Copy link
Copy Markdown
Contributor

looked though it and LGTM

@clebertsuconic

Copy link
Copy Markdown
Contributor

(I am assuming the tests reproduced the issue and no regressions happened on the whole testsuite) if those are good.. I aprove the changes.

@jbertram
jbertram merged commit 18a9d87 into apache:main Aug 24, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants