apache / apache/shenyu

[BUG] DiscardOldestPolicy causes infinite recursion → StackOverflowError with MemorySafeLinkedBlockingQueue

Open
#6,610 1 comment 0 reactions 0 assignees View on GitHub
priority: critical type: bug
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.