[
https://issues.apache.org/jira/browse/CXF-9234?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Freeman Yue Fang resolved CXF-9234.
-----------------------------------
Fix Version/s: 4.1.9
4.2.4
Resolution: Fixed
> Concurrent DynamicClientFactory.createClient for the same WSDL url corrupts
> the cached schema DOM and spins forever at 100% CPU
> -------------------------------------------------------------------------------------------------------------------------------
>
> Key: CXF-9234
> URL: https://issues.apache.org/jira/browse/CXF-9234
> Project: CXF
> Issue Type: Bug
> Components: Simple Frontend
> Affects Versions: 4.2.2
> Environment: CXF 4.2.2, Woodstox 7.2.0
> xerces:xercesImpl:2.12.2
> Java Azul 25.0.3
> Arch Linux, also reproduced on Windows 11
> Reporter: David Richter
> Assignee: Freeman Yue Fang
> Priority: Major
> Fix For: 4.1.9, 4.2.4
>
> Attachments: cxf-concurrent-schema-clone-repro.zip
>
>
> Two threads calling `DynamicClientFactory.createClient(wsdlUrl, ...)` for the
> *same* url can enter an unbounded spin at 100% CPU and never return. The
> thread is RUNNABLE, ignores interrupts, and keeps burning a core until the
> JVM exits.
> h2. Stacktrace:
>
> {code:java}
> java.lang.Thread.State: RUNNABLE
> at java.util.WeakHashMap.get([email protected]/WeakHashMap.java:416)
> at org.apache.xerces.dom.CoreDocumentImpl.setUserData(Unknown Source)
> at org.apache.xerces.dom.NodeImpl.setUserData(Unknown Source)
> at
> org.apache.cxf.staxutils.StaxUtils$LocationUserDataHandler.handle(StaxUtils.java:1648)
> at
> org.apache.xerces.dom.CoreDocumentImpl.callUserDataHandlers(Unknown Source)
> at
> org.apache.xerces.dom.CoreDocumentImpl.callUserDataHandlers(Unknown Source)
> at org.apache.xerces.dom.NodeImpl.cloneNode(Unknown Source)
> at org.apache.xerces.dom.ChildNode.cloneNode(Unknown Source)
> at org.apache.xerces.dom.ParentNode.cloneNode(Unknown Source)
> at org.apache.xerces.dom.ElementImpl.cloneNode(Unknown Source)
> at org.apache.xerces.dom.ParentNode.cloneNode(Unknown Source)
> at org.apache.xerces.dom.ElementImpl.cloneNode(Unknown Source)
> at org.apache.xerces.dom.ParentNode.cloneNode(Unknown Source)
> at org.apache.xerces.dom.ElementImpl.cloneNode(Unknown Source)
> at org.apache.xerces.dom.ParentNode.cloneNode(Unknown Source)
> at org.apache.xerces.dom.ElementImpl.cloneNode(Unknown Source)
> at
> org.apache.cxf.endpoint.dynamic.DynamicClientFactory.cloneNode(DynamicClientFactory.java:986)
> at
> org.apache.cxf.endpoint.dynamic.DynamicClientFactory.removeImportElement(DynamicClientFactory.java:946)
> at
> org.apache.cxf.endpoint.dynamic.DynamicClientFactory.addSchemas(DynamicClientFactory.java:593)
> at
> org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java:337)
> at
> org.apache.cxf.endpoint.dynamic.DynamicClientFactory.createClient(DynamicClientFactory.java:225)
>
> ...{code}
> h2. Cause (AI generated during investigation but seems legit):
> 1. `WSDLManagerImpl` caches the parsed `Definition` — and its schema DOM —
> per WSDL url. Map access is synchronized, but the cached DOM is handed to
> concurrent callers unsynchronized.
> 2. `DynamicClientFactory.removeImportElement` deep-clones that schema when it
> contains an `xs:import`/`xs:include` (`DynamicClientFactory:946`; `owner ==
> document`, so this delegates to `node.cloneNode(deep)` on the cached
> document).
> 3. Every cloned node re-fires `StaxUtils$LocationUserDataHandler.handle` →
> `dst.setUserData(...)` (`StaxUtils:1643-1650`), writing into the **source**
> document's userData map.
> 4. That map is not thread safe in any DOM implementation — `WeakHashMap` in
> Xerces-J, `HashMap` in the JDK DOM — so concurrent clones corrupt it into a
> cycle and the lookups then loop forever.
> h2. Reproducer project (AI generated manually checked)
> `cxf-concurrent-schema-clone-repro.zip` — self-contained Maven project, Maven
> wrapper included, no network service needed.
> {code:java}
> ./mvnw test # JDK built-in DOM
> ./mvnw test -Pxerces # Xerces-J 2.12.2
> {code}
> Both fail on `concurrentDeepCloneOfSharedSchemaMustNotHang`, printing the
> worker stacks to stderr. Select a CXF version with `-Dcxf.version=4.1.4`.
> The project has three tests: the failing one deep-clones a single shared
> location-tracked schema from N threads (what step 2 above does); a
> single-threaded control makes the same number of clones in ~4 s, showing the
> problem is the concurrency and not the schema size; and one exercises the
> real `createClient` path with two threads on a shared bus — that one is
> timing dependent and passed on an idle machine here.
> It is a race, so the failing test retries fresh rounds for up to 180 s before
> giving up (it tripped on round 1–3 on a 22-core box).
> `observed-thread-dumps.txt` in the archive holds real dumps from both DOM
> variants in case it does not trip on your hardware.
> Note: once it trips, the worker threads cannot be stopped — expect to kill
> the JVM.
> h2. Workaround
> Build each client on its own Bus, so the per-bus WSDLManager cache - and
> therefore the
> schema DOM - is not shared between threads.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)