[BUG] DiscardOldestPolicy causes infinite recursion → StackOverflowError with MemorySafeLinkedBlockingQueue
- Dominant language
- Java
- Stars
- 8.8k
- Forks
- 3.1k
- Avg merge
- 7d 1h
- Merged PRs (30d)
- 85
Description
- Severity: Critical
- Location:
`shenyu-common/src/main/java/org/apache/shenyu/common/concurrent/DiscardOldestPolicy.java:28-31`; `shenyu-common/src/main/java/org/apache/shenyu/common/concurrent/MemorySafeLinkedBlockingQueue.java:107-113`
-
Description:
`DiscardOldestPolicy.reject(e, queue)` does `queue.poll(); queue.offer(e);`. The `queue` is the `MemorySafeLinkedBlockingQueue` itself (passed as `this`). `queue.offer(e)` dispatches to the overridden `offer`, which re-checks `hasRemainedMemory()`. `Runtime.freeMemory()` does not change in the microsecond window (`maxAvailable` refreshed only every 50ms by `MemoryLimitCalculator`), so the check is still false → `rejector.reject(e, this)` re-enters `DiscardOldestPolicy.reject`. The queue shrinks via `poll()`; once empty `poll()` returns null but `offer(e)` still recurses forever. Result: `StackOverflowError` instead of "discard oldest" — happening precisely in the low-memory condition the queue exists to handle. The `Rejector` interface documents `DiscardOldestPolicy` as a supported implementation.
-
Impact:
Any deployment wiring `queue.setRejector(new DiscardOldestPolicy<>())` crashes the offering thread (often a netty/transport worker) the first time free memory drops below `maxFreeMemory`.
-
Suggested fix:
Add a bypass method (e.g. `offerIgnoringMemory`) that calls `super.offer(e)`; have `DiscardOldestPolicy.reject` use it. Or guard `reject` to not re-invoke the memory-checked `offer`.
-
Confidence: High
- Related existing: none — #6445 was `put` rejecting *after* enqueue (different method, fixed); this is unconditional recursion in `offer` via the discard-oldest rejector.
---
_Identified during the 2026-08-02 deep re-scan; full list in [`docs/scan2-2026-08-02/00-consolidated-critical-high.md`](docs/scan2-2026-08-02/00-consolidated-critical-high.md)._
Contributor guide
No contributing guide indexed for this repository
Research direction
Read DiscardOldestPolicy.java:28-31 and MemorySafeLinkedBlockingQueue.java:107-113 first, then trace the rejector and offer paths under the low-memory condition. Verify that discarding the oldest item no longer re-enters the memory check or recurses after the queue becomes empty, and that the offering thread completes without StackOverflowError.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100