dong0713 opened a new issue, #10674:
URL: https://github.com/apache/rocketmq/issues/10674

   ### Before Creating the Bug Report
   
   - [x] I found a bug, not just asking a question
   - [x] I have searched the GitHub Issues and believe this is not a duplicate
   - [x] I have confirmed that this bug belongs to the current repository
   
   ### Runtime platform environment
   
   Any (logic bug, environment-independent)
   
   ### RocketMQ version
   
   branch: develop (5.5.0)
   
   ### JDK Version
   
   JDK 8
   
   ### Describe the Bug
   
   PR #10579 recently fixed an integer overflow in `DefaultElectPolicy`'s 
comparator, where a `long` offset delta was cast to `int` via `(int) 
(o2.getMaxOffset() - o1.getMaxOffset())`. When the offset difference exceeds 
`Integer.MAX_VALUE`, the cast overflows and the comparator returns the wrong 
ordering.
   
   After scanning the codebase, I found **three more comparators** with the 
same `long`-subtraction-cast-to-`int` overflow pattern. All three involve 
`long` fields (offsets / timestamps / counters) and all three are in production 
hot paths.
   
   #### 1. `PopRequest.COMPARATOR` (broker, long-polling)
   
   
`broker/src/main/java/org/apache/rocketmq/broker/longpolling/PopRequest.java:95,100`
   
   ```java
   public static final Comparator<PopRequest> COMPARATOR = (o1, o2) -> {
       int ret = (int) (o1.getExpired() - o2.getExpired());   // line 95: long 
timestamp delta
       if (ret != 0) {
           return ret;
       }
       ret = (int) (o1.op - o2.op);                             // line 100: 
long counter delta
       if (ret != 0) {
           return ret;
       }
       return -1;
   };
   ```
   
   - `expired` is a `long` timestamp (ms). Two requests far apart in time can 
overflow `int`.
   - `op` is a `long` initialized from `COUNTER.getAndIncrement()` starting at 
`Long.MIN_VALUE` (line 29, 34). **Overflow here is essentially guaranteed** for 
any non-trivial number of PopRequests, since the counter walks from 
`Long.MIN_VALUE` upward and deltas between early and late requests easily 
exceed `Integer.MAX_VALUE`.
   - This comparator backs a `ConcurrentSkipListSet` for pop long-polling — a 
broken comparator corrupts the ordered set's invariants, causing subtle request 
ordering/delivery bugs.
   
   #### 2. `PopCheckPoint.compareTo` (store, pop checkpoint)
   
   `store/src/main/java/org/apache/rocketmq/store/pop/PopCheckPoint.java:215`
   
   ```java
   @Override
   public int compareTo(PopCheckPoint o) {
       return (int) (this.getStartOffset() - o.getStartOffset());
   }
   ```
   
   - `startOffset` is a `long` queue offset. A long-running broker can produce 
queue offsets whose delta exceeds `Integer.MAX_VALUE`. The `Comparable` 
contract is relied upon by sorted collections; a broken `compareTo` violates 
sort invariants.
   
   #### 3. `PopReviveService.genSortList` (broker, pop revival)
   
   
`broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java:728`
   
   ```java
   sortList.sort((o1, o2) -> (int) (o1.getReviveOffset() - 
o2.getReviveOffset()));
   ```
   
   - `reviveOffset` is a `long` commit-log offset. Same overflow class as 
#10579.
   
   ### Impact
   
   - `PopRequest.COMPARATOR` is the most severe: the `op` counter starts at 
`Long.MIN_VALUE`, so the overflow is not theoretical — it triggers for real 
workloads, corrupting the `ConcurrentSkipListSet` that orders pop long-polling 
requests. A broken comparator in a `SortedSet` can cause requests to be 
misplaced, starved, or delivered out of order.
   - `PopCheckPoint.compareTo` and `PopReviveService` sort affect pop 
retry/checkpoint ordering correctness under large offsets.
   
   All three are the **exact same bug class** as the already-fixed #10579.
   
   ### Steps to Reproduce
   
   For `PopRequest.COMPARATOR` (the guaranteed-overflow case):
   
   ```java
   // op counter starts at Long.MIN_VALUE; after many requests the delta 
overflows int
   PopRequest a = ...; // op = Long.MIN_VALUE
   PopRequest b = ...; // op = Long.MIN_VALUE + (long)Integer.MAX_VALUE + 2
   int cmp = PopRequest.COMPARATOR.compare(a, b);
   // (int)(a.op - b.op) overflows -> wrong sign -> wrong ordering
   ```
   
   ### What Did You Expect to See?
   
   Comparators over `long` fields should use `Long.compare(a, b)` (and 
`Integer.compare` for the `int` tiebreaker) instead of 
subtraction-cast-to-`int`, exactly as #10579 did for `DefaultElectPolicy`.
   
   ### What Did You See Instead?
   
   Subtraction-cast-to-`int`, which overflows when the `long` delta exceeds 
`Integer.MAX_VALUE`.
   
   ### Additional Context
   
   This is a systematic scan of the same overflow class fixed by #10579. Happy 
to submit a PR mirroring the #10579 fix (`Long.compare` / `Integer.compare`) if 
the maintainers agree these are real.


-- 
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