Skip to content

Null-check packet allocations in allocForSending and its callers - #11086

Merged
thebentern merged 3 commits into
developfrom
fix-null-deref-allocforsending
Jul 20, 2026
Merged

Null-check packet allocations in allocForSending and its callers#11086
thebentern merged 3 commits into
developfrom
fix-null-deref-allocforsending

Conversation

@caveman99

@caveman99 caveman99 commented Jul 20, 2026

Copy link
Copy Markdown
Member

Router::allocForSending() dereferenced packetPool.allocZeroed() without a null check. Sibling of 0ae44d7.

The pool is heap-backed on ARCH_STM32WL and BOARD_HAS_PSRAM, so allocation can fail. Guarding allocForSending() alone moves the deref to its callers, so the allocDataPacket() wrappers and all unguarded call sites are guarded too. 31 call sites: 29 guarded, 2 return the pointer directly.

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability by safely handling packet/protobuf allocation failures during outgoing mesh communication.
    • Prevented potential crashes and invalid sends across routing ACK/Nak, MQTT local ACK generation, and multiple telemetry and module message paths (including sensors, status, position/PLI, audio, games, neighbor info, admin replies, key verification, store-and-forward, and paxcounter).
    • Messages/telemetry now fail gracefully with early exit/backoff instead of dereferencing null allocations.

@caveman99 caveman99 added the bugfix Pull request that fixes bugs label Jul 20, 2026
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The PR adds null checks across packet allocation primitives, shared packet builders, administrative reply handlers, telemetry paths, and mesh module send paths. Failed allocations now return safely, with detection-message paths also releasing temporary buffers before returning.

Packet allocation safety

Layer / File(s) Summary
Allocation primitives
src/mesh/Router.cpp
Router::allocForSending() returns nullptr when packet-pool allocation fails.
Packet-building helper guards
src/mesh/SinglePortModule.h, src/modules/SerialModule.h, src/mesh/ProtobufModule.h, src/mesh/MeshModule.cpp, src/modules/ReplyModule.cpp
Shared packet builders check allocation results before initializing packet fields or payloads.
Module send-path guards
src/graphics/niche/InkHUD/.../MenuApplet.cpp, src/modules/*, src/mqtt/MQTT.cpp
Send, payload, ACK/NACK, and module paths return early on allocation failure; detection sensor paths delete temporary message buffers before returning.
Administrative reply guards
src/modules/AdminModule.cpp
Getter handlers return before setting protobuf reply fields when reply allocation fails.
Telemetry send-state guards
src/modules/Telemetry/*
Telemetry paths mark failed allocations invalid and skip packet replacement, transmission, and related notifications.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

Suggested reviewers: ndoo

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is off-template and omits the required attestation checklist and testing/device details. Replace it with the repo template sections and complete the test/attestation checklist, including any relevant devices tested.
Docstring Coverage ⚠️ Warning Docstring coverage is 29.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding null checks around packet allocation and callers.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-null-deref-allocforsending

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mesh/MeshModule.cpp`:
- Around line 59-61: Update every caller of allocAckNak() to handle a nullptr
result before accessing or passing the packet onward. In
RoutingModule::sendAckNak(), check p before dereferencing p->want_ack; in
allocErrorResponse(), check the allocation result before calling setReplyTo(),
preserving the existing failure behavior where appropriate.

In `@src/mesh/ProtobufModule.h`:
- Around line 47-48: Update StoreForwardModule::sendMessage() to check whether
allocDataProtobuf(payload) returned nullptr before dereferencing p or accessing
packet fields, and return early on allocation failure while preserving the
existing send flow for valid packets.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a9b6c05d-5301-4d73-9b1e-c6f0f833ec2d

📥 Commits

Reviewing files that changed from the base of the PR and between 829ff80 and 1c8d43e.

📒 Files selected for processing (18)
  • src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp
  • src/mesh/MeshModule.cpp
  • src/mesh/ProtobufModule.h
  • src/mesh/Router.cpp
  • src/mesh/SinglePortModule.h
  • src/modules/CannedMessageModule.cpp
  • src/modules/DetectionSensorModule.cpp
  • src/modules/DropzoneModule.cpp
  • src/modules/PositionModule.cpp
  • src/modules/RangeTestModule.cpp
  • src/modules/ReplyBotModule.cpp
  • src/modules/ReplyModule.cpp
  • src/modules/SerialModule.cpp
  • src/modules/SerialModule.h
  • src/modules/StatusMessageModule.cpp
  • src/modules/StoreForwardModule.cpp
  • src/modules/esp32/AudioModule.cpp
  • src/modules/games/GamesModule.cpp

Comment thread src/mesh/MeshModule.cpp
Comment on lines 59 to +61
meshtastic_MeshPacket *p = router->allocForSending();
if (!p)
return nullptr;

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.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Propagate the nullable result to every allocAckNak() caller.

This guard makes allocAckNak() return nullptr, but RoutingModule::sendAckNak() immediately dereferences p->want_ack, and allocErrorResponse() passes the result to setReplyTo() without checking it. Add failure handling at both callers before they touch the packet; otherwise the allocation-failure fix still leaves a crash path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mesh/MeshModule.cpp` around lines 59 - 61, Update every caller of
allocAckNak() to handle a nullptr result before accessing or passing the packet
onward. In RoutingModule::sendAckNak(), check p before dereferencing
p->want_ack; in allocErrorResponse(), check the allocation result before calling
setReplyTo(), preserving the existing failure behavior where appropriate.

Comment thread src/mesh/ProtobufModule.h
@caveman99

Copy link
Copy Markdown
Member Author

Both findings were valid and are fixed.

Rather than patch the two reported sites, I computed the transitive closure of functions that can now return nullptr. Twelve functions are nullable once the contract propagates: allocForSending, allocDataPacket, allocReply, allocDataProtobuf, allocAckNak, allocErrorResponse, allocAtakPli, allocPositionPacket, preparePayload, gameAllocDataPacket, getForPhone, sendConditions.

That surfaced 23 unguarded dereference sites at the second tier, including the two reported. All are now guarded: AdminModule x8, the seven Telemetry senders, PaxcounterModule, KeyVerificationModule x2, NeighborInfoModule, RoutingModule, StoreForwardModule, MQTT.

One reported site needed no change. At AdminModule.cpp:719 the only dereference is already guarded by if (mp.pki_encrypted && myReply).

Totals across both commits: 55 call sites guarded, 0 unguarded dereferences remaining.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/modules/Telemetry/AirQualityTelemetry.cpp`:
- Around line 466-468: Preserve the false result on packet allocation failure
without returning before the power-saving sleep-scheduling blocks: in
src/modules/Telemetry/AirQualityTelemetry.cpp lines 466-468,
src/modules/Telemetry/EnvironmentTelemetry.cpp lines 663-665,
src/modules/Telemetry/HealthTelemetry.cpp lines 250-252, and
src/modules/Telemetry/PowerTelemetry.cpp lines 277-279, track telemetry-send
failure and skip only packet setup/sending so each function still reaches its
existing five-second wake/sleep scheduling logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5dc69ee1-62e7-430d-9ec1-a90d25c465c1

📥 Commits

Reviewing files that changed from the base of the PR and between 1c8d43e and 8b39df5.

📒 Files selected for processing (13)
  • src/modules/AdminModule.cpp
  • src/modules/KeyVerificationModule.cpp
  • src/modules/NeighborInfoModule.cpp
  • src/modules/RoutingModule.cpp
  • src/modules/StoreForwardModule.cpp
  • src/modules/Telemetry/AirQualityTelemetry.cpp
  • src/modules/Telemetry/DeviceTelemetry.cpp
  • src/modules/Telemetry/EnvironmentTelemetry.cpp
  • src/modules/Telemetry/HealthTelemetry.cpp
  • src/modules/Telemetry/HostMetrics.cpp
  • src/modules/Telemetry/PowerTelemetry.cpp
  • src/modules/esp32/PaxcounterModule.cpp
  • src/mqtt/MQTT.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/modules/StoreForwardModule.cpp

Comment on lines +466 to +468
meshtastic_MeshPacket *p = allocDataProtobuf(m);
if (!p)
return false;

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Do not return before power-saving sleep is scheduled.

When allocation fails, these early returns skip sleepOnNextExecution and the five-second wake/sleep scheduling for power-saving SENSOR nodes, leaving them awake until the next telemetry interval. Preserve the false result while continuing through the sleep-scheduling block—for example, mark the telemetry send as failed and skip only packet setup/sending.

  • src/modules/Telemetry/AirQualityTelemetry.cpp#L466-L468: avoid returning before lines 506-513 execute.
  • src/modules/Telemetry/EnvironmentTelemetry.cpp#L663-L665: avoid returning before lines 702-708 execute.
  • src/modules/Telemetry/HealthTelemetry.cpp#L250-L252: avoid returning before lines 276-282 execute.
  • src/modules/Telemetry/PowerTelemetry.cpp#L277-L279: avoid returning before lines 303-309 execute.
📍 Affects 4 files
  • src/modules/Telemetry/AirQualityTelemetry.cpp#L466-L468 (this comment)
  • src/modules/Telemetry/EnvironmentTelemetry.cpp#L663-L665
  • src/modules/Telemetry/HealthTelemetry.cpp#L250-L252
  • src/modules/Telemetry/PowerTelemetry.cpp#L277-L279
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/modules/Telemetry/AirQualityTelemetry.cpp` around lines 466 - 468,
Preserve the false result on packet allocation failure without returning before
the power-saving sleep-scheduling blocks: in
src/modules/Telemetry/AirQualityTelemetry.cpp lines 466-468,
src/modules/Telemetry/EnvironmentTelemetry.cpp lines 663-665,
src/modules/Telemetry/HealthTelemetry.cpp lines 250-252, and
src/modules/Telemetry/PowerTelemetry.cpp lines 277-279, track telemetry-send
failure and skip only packet setup/sending so each function still reaches its
existing five-second wake/sleep scheduling logic.

Allocation failure now marks the telemetry invalid instead of returning
early, so power-saving SENSOR nodes still arm deep sleep.
@caveman99

Copy link
Copy Markdown
Member Author

Valid, and fixed in 5076999.

The early return false skipped the pre-sleep block at the end of each sender, which the code explicitly documents must run even when nothing was sent, otherwise a power-saving SENSOR node stays awake until the next interval and drains its battery. Allocation failure now sets validTelemetry = false and skips only the packet setup and send, so control still reaches the sleep scheduling and the function still returns false. The existing LOG_WARN in that block already reads "unavailable this cycle, sleep without sending", which covers allocation failure correctly.

Scope checked: only these four senders have the sleep mechanism. DeviceTelemetry, HostMetrics and PaxcounterModule have no such block, so their early returns are left as they are.

git diff -w for the four files shows only the guard replacement and one closing brace, so the send path is unchanged apart from indentation. native-windows builds clean and all four objects compile.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
src/modules/Telemetry/AirQualityTelemetry.cpp (1)

494-497: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use snprintf instead of sprintf to prevent potential buffer overflows.

The code uses sprintf to format the notification message, which writes to a fixed-size buffer without bounds checking. Even though the format string is relatively short, it is safer and standard practice to use snprintf with sizeof to ensure the buffer bounds are strictly respected.

  • src/modules/Telemetry/AirQualityTelemetry.cpp#L494-L497: Replace sprintf(notification->message, ...) with snprintf(notification->message, sizeof(notification->message), ...).
  • src/modules/Telemetry/EnvironmentTelemetry.cpp#L690-L693: Replace sprintf(notification->message, ...) with snprintf(notification->message, sizeof(notification->message), ...).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/modules/Telemetry/AirQualityTelemetry.cpp` around lines 494 - 497,
Replace sprintf with bounded snprintf for notification->message in
AirQualityTelemetry.cpp lines 494-497 and EnvironmentTelemetry.cpp lines
690-693, passing sizeof(notification->message) as the buffer size while
preserving the existing format and arguments.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/modules/Telemetry/AirQualityTelemetry.cpp`:
- Around line 494-497: Replace sprintf with bounded snprintf for
notification->message in AirQualityTelemetry.cpp lines 494-497 and
EnvironmentTelemetry.cpp lines 690-693, passing sizeof(notification->message) as
the buffer size while preserving the existing format and arguments.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f4ce811a-068b-41cb-9676-cecb3bcb35a0

📥 Commits

Reviewing files that changed from the base of the PR and between 8b39df5 and 5076999.

📒 Files selected for processing (4)
  • src/modules/Telemetry/AirQualityTelemetry.cpp
  • src/modules/Telemetry/EnvironmentTelemetry.cpp
  • src/modules/Telemetry/HealthTelemetry.cpp
  • src/modules/Telemetry/PowerTelemetry.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/modules/Telemetry/HealthTelemetry.cpp

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

⚡ Try this PR in the Web Flasher

Flash this PR in the Web Flasher

firmware commit boards expires

Warning

This is an automated, unreviewed CI test build. Back up your device configuration
before flashing, and only flash devices you are able to recover.

Supported boards built by this PR (30)
Device Board Platform
Crowpanel Adv 3.5 TFT elecrow-adv-35-tft esp32-s3
Heltec HT62 heltec-ht62-esp32c3-sx1262 esp32-c3
Heltec Mesh Node 096 heltec-mesh-node-t096 nrf52840
Heltec Mesh Node T1 heltec-mesh-node-t1 nrf52840
Heltec Mesh Node T114 heltec-mesh-node-t114 nrf52840
Heltec V3 heltec-v3 esp32-s3
Heltec V4 heltec-v4 esp32-s3
Meshnology W10 meshnology_w10 esp32-s3
Raspberry Pi Pico pico rp2040
Raspberry Pi Pico W picow rp2040
RAK WisMesh Pocket V3 rak_wismesh_pocket nrf52840
RAK WisMesh Pod rak_wismesh_pod nrf52840
RAK WisMesh Repeater Mini V2 rak_wismesh_repeater_mini nrf52840
RAK WisMesh Tag rak_wismeshtag nrf52840
RAK WisBlock 11200 rak11200 esp32
RAK WisBlock 11310 rak11310 rp2040
RAK3312 rak3312 esp32-s3
RAK WisBlock 4631 rak4631 nrf52840
Seeed SenseCAP Mesh-Tracker-X1 seeed_mesh_tracker_X1 nrf52840
Seeed Wio Tracker L1 seeed_wio_tracker_L1 nrf52840
Seeed Xiao NRF52840 Kit seeed_xiao_nrf52840_kit nrf52840
Seeed Xiao ESP32-S3 seeed-xiao-s3 esp32-s3
Station G2 station-g2 esp32-s3
Station G3 station-g3 esp32-s3
LILYGO T-Deck t-deck-tft esp32-s3
LILYGO T-Echo t-echo nrf52840
LILYGO T-Echo Plus t-echo-plus nrf52840
LILYGO T-Impulse Plus t-impulse-plus nrf52840
LilyGo T3-C6 tlora-c6 esp32-c6
Seeed SenseCAP T1000-E tracker-t1000-e nrf52840

Build artifacts expire on 2026-08-19. Updated for 5076999.

@thebentern
thebentern merged commit fb75410 into develop Jul 20, 2026
104 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Pull request that fixes bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants