Skip to content

fix: guard NPE/IOOBE edge cases in admin, transaction, store and http client - #10733

Open
btlqql wants to merge 1 commit into
apache:developfrom
btlqql:fix/round2-npe-and-ioobe-guards
Open

fix: guard NPE/IOOBE edge cases in admin, transaction, store and http client#10733
btlqql wants to merge 1 commit into
apache:developfrom
btlqql:fix/round2-npe-and-ioobe-guards

Conversation

@btlqql

@btlqql btlqql commented Jul 31, 2026

Copy link
Copy Markdown

Motivation

Four edge-case crashes found by code review (verified against the current develop branch):

  1. AdminBrokerProcessor.queryCorrectionOffset NPE (broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java)
    correctionOffset only 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) is null and the ternary auto-unboxes it → NPE, failing the QUERY_CORRECTION_OFFSET admin RPC. Guarded with a null check.

  2. ConsumeQueue.estimateMessageCount NPE (store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java)
    consumeQueueExt.get(tagCode) returns null for CQ entries written before ext was enabled (or when a previous ext put fell back to a plain tagsCode), so ext.getTagsCode() threw NPE and broke consumer-lag metrics. Skip when ext is null (the filter already handles a null CqExtUnit).

  3. TransactionalMessageServiceImpl IndexOutOfBoundsException (broker/src/main/java/org/apache/rocketmq/broker/transaction/queue/TransactionalMessageServiceImpl.java)
    opMsg can be a non-null empty list, so opMsg.get(opMsg.size() - 1) threw IndexOutOfBoundsException and aborted the entire transaction-check pass for all queues. Guarded with !opMsg.isEmpty().

  4. HttpTinyClient NPE on error responses without a body (common/src/main/java/org/apache/rocketmq/common/utils/HttpTinyClient.java)
    HttpURLConnection.getErrorStream() returns null when the error response has no body; IOTinyUtils.toString(null, ...) threw NPE and broke namesrv discovery via DefaultTopAddressing. Guarded both httpGet and httpPost.

Verification

mvn -pl broker -am compile passes on the build server.

Diff

4 files changed, +15 / -6.

… 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 RockteMQ-AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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. Extracts correctionOffset.get(queueId) into a local variable, eliminating both the NPE from auto-unboxing null Long and the redundant double get() call. Clean.

  • [Info] TransactionalMessageServiceImpl.java:296 — Correct IOOBE guard. !opMsg.isEmpty() short-circuits before opMsg.get(opMsg.size() - 1). Operator precedence is correct (&& binds tighter than ||).

  • [Info] HttpTinyClient.java (httpGet + httpPost) — Proper null check for conn.getErrorStream(). Both methods are consistently guarded. Setting resp = null when no error body is reasonable since callers should check status code first.

  • [Info] ConsumeQueue.java:estimateMessageCount — Correct fallback: when consumeQueueExt.get(tagCode) returns null (entry written before ext was enabled), the original tagCode from the CQ entry is preserved. The downstream filter.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 in HttpTinyClient — 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 RockteMQ-AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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() before opMsg.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 in filter.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 RockteMQ-AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Defensive fix with proper validation and test coverage. LGTM.


Automated review by github-manager-bot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants