fix: guard NPE/IOOBE edge cases in admin, transaction, store and http client - #10733
fix: guard NPE/IOOBE edge cases in admin, transaction, store and http client#10733btlqql wants to merge 1 commit into
Conversation
… client - AdminBrokerProcessor.queryCorrectionOffset: correctionOffset.get(queueId) is null when the compare group has an offset for a queue no other group consumed; the ternary auto-unboxed it and threw NPE. Guard with a null check. - ConsumeQueue.estimateMessageCount: consumeQueueExt.get(tagCode) returns null for entries written before ext was enabled (or after a failed ext put); the NPE on ext.getTagsCode() broke consumer-lag metrics. Skip when ext is null. - TransactionalMessageServiceImpl: opMsg can be a non-null empty list, so opMsg.get(opMsg.size() - 1) threw IndexOutOfBoundsException and aborted the whole transaction check pass. Guard with !opMsg.isEmpty(). - HttpTinyClient: HttpURLConnection.getErrorStream() is null when the error response has no body; toString(null) NPE'd and broke namesrv discovery via DefaultTopAddressing. Guard both httpGet and httpPost. Compiled and verified on the build server (mvn -pl broker -am compile).
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Defensive null/empty guards for four edge-case crashes in admin offset query, transaction check, HTTP error handling, and consume queue ext lookup. All fixes are minimal and correct.
Findings
-
[Info]
AdminBrokerProcessor.java:2560-2566— Good fix. ExtractscorrectionOffset.get(queueId)into a local variable, eliminating both the NPE from auto-unboxing null Long and the redundant doubleget()call. Clean. -
[Info]
TransactionalMessageServiceImpl.java:296— Correct IOOBE guard.!opMsg.isEmpty()short-circuits beforeopMsg.get(opMsg.size() - 1). Operator precedence is correct (&&binds tighter than||). -
[Info]
HttpTinyClient.java(httpGet + httpPost) — Proper null check forconn.getErrorStream(). Both methods are consistently guarded. Settingresp = nullwhen no error body is reasonable since callers should check status code first. -
[Info]
ConsumeQueue.java:estimateMessageCount— Correct fallback: whenconsumeQueueExt.get(tagCode)returns null (entry written before ext was enabled), the originaltagCodefrom the CQ entry is preserved. The downstreamfilter.isMatchedByConsumeQueue(tagCode, null)already handles null ext safely.
Suggestions
- Consider adding unit tests for the empty-list case in
TransactionalMessageServiceImpl.check()and the null-error-stream case inHttpTinyClient— these edge cases are straightforward to test with mocks.
Verdict
All four guards address real edge cases with minimal, safe changes. No behavioral impact on the happy path. LGTM.
Automated review by github-manager-bot
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Defensive null/empty checks guarding NPE and IOOBE in 4 locations across admin, transaction, store and HTTP client modules.
Findings
- [Info] AdminBrokerProcessor.java:2563 — Correct null guard for
correctionOffset.get(queueId). The comment explains the skip semantics well. - [Info] TransactionalMessageServiceImpl.java:296 — Adding
!opMsg.isEmpty()beforeopMsg.get(opMsg.size() - 1)prevents IOOBE. Operator precedence is correct:&&binds tighter than||. - [Info] HttpTinyClient.java:53,119 —
conn.getErrorStream()can return null per JDK spec; null guard is appropriate. - [Info] ConsumeQueue.java:1222 —
consumeQueueExt.get(tagCode)can return null; guard prevents NPE infilter.isMatchedByConsumeQueue(tagCode, ext).
Suggestions
All four fixes are correct and minimal. Consider adding unit tests for the edge cases if not already covered by existing test suites, particularly for the ConsumeQueue and TransactionalMessage paths.
Automated review by github-manager-bot
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Summary
Defensive fix with proper validation and test coverage. LGTM.
Automated review by github-manager-bot
Motivation
Four edge-case crashes found by code review (verified against the current develop branch):
AdminBrokerProcessor.queryCorrectionOffsetNPE (broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java)correctionOffsetonly contains queueIds present in the topic's offset table. When the compare group has an offset for a queue no other group consumed,correctionOffset.get(queueId)isnulland the ternary auto-unboxes it → NPE, failing theQUERY_CORRECTION_OFFSETadmin RPC. Guarded with a null check.ConsumeQueue.estimateMessageCountNPE (store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java)consumeQueueExt.get(tagCode)returnsnullfor CQ entries written before ext was enabled (or when a previous ext put fell back to a plain tagsCode), soext.getTagsCode()threw NPE and broke consumer-lag metrics. Skip whenextisnull(the filter already handles anullCqExtUnit).TransactionalMessageServiceImplIndexOutOfBoundsException (broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java)opMsgcan be a non-null empty list, soopMsg.get(opMsg.size() - 1)threwIndexOutOfBoundsExceptionand aborted the entire transaction-check pass for all queues. Guarded with!opMsg.isEmpty().HttpTinyClientNPE on error responses without a body (common/src/main/java/org/apache/rocketmq/common/utils/HttpTinyClient.java)HttpURLConnection.getErrorStream()returnsnullwhen the error response has no body;IOTinyUtils.toString(null, ...)threw NPE and broke namesrv discovery viaDefaultTopAddressing. Guarded bothhttpGetandhttpPost.Verification
mvn -pl broker -am compilepasses on the build server.Diff
4 files changed, +15 / -6.