Aias00 opened a new issue, #6857:
URL: https://github.com/apache/shenyu/issues/6857

   ## Description
   `findUpstreamListBySelectorId` returns 
`task.getHealthyUpstream().get(selectorId)` — a direct reference to the live 
`ArrayList` stored in `UpstreamCheckTask.healthyUpstream` (a `ConcurrentMap` of 
plain `ArrayList` values). The health-check thread modifies this same list 
under `synchronized(lock)`: `putToMap` calls `list.add(upstream)` and 
`removeFromMap` calls `list.remove(upstream)`. However, the readers 
(`DividePlugin:94`, `WebSocketPlugin:92`, `ApacheDubboGrayLoadBalance:57`, 
`DefaultRetryStrategy:109`) iterate and index the returned list on request 
threads WITHOUT acquiring `lock`. `ArrayList` is not thread-safe: a concurrent 
`add` (which may trigger `Arrays.copyOf` resize) or `remove` (which shifts 
elements via `System.arraycopy`) while a reader calls `size()` then `get(i)` 
can produce `IndexOutOfBoundsException`, null reads, or stale/inconsistent list 
state.
   
   ## Location
   - 
`shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCacheManager.java:128`
   - 
`shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/cache/UpstreamCheckTask.java:289-292,305-308,355`
   - 
`shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/src/main/java/org/apache/shenyu/plugin/divide/DividePlugin.java:94`
   
   ## Impact
   Occasional `IndexOutOfBoundsException` or NPE in the load balancer during a 
health-check cycle, causing intermittent 500 errors for proxied requests. Also 
possible: load balancer sees a partially-updated list (missing or phantom 
upstreams), routing to a stale or non-existent endpoint.
   
   ## Suggested fix
   Either (a) return a snapshot copy from `findUpstreamListBySelectorId` (`new 
ArrayList<>(list)` under `synchronized(lock)`), or (b) change the 
`healthyUpstream` values to `CopyOnWriteArrayList` so readers get a consistent 
snapshot. Option (b) is lower overhead for the read-heavy path.
   
   ## Related existing
   None — distinct from #6570 (BaseDataCache.removeSelectData/removeRuleData 
mutate live list in place) which covers `shenyu-common`'s selector/rule cache, 
and distinct from N35 (admin-side `UpstreamCheckService.fetchUpstreamData` 
LinkedList in `shenyu-admin`). This covers the gateway-side 
`UpstreamCacheManager`/`UpstreamCheckTask` in `shenyu-loadbalancer`.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to