Skip to content

[Bugfix] Whitelist remove / scan response timer crash on invalid pointers - #435

Merged
h2zero merged 2 commits into
masterfrom
bugfix/wl
Aug 1, 2026
Merged

[Bugfix] Whitelist remove / scan response timer crash on invalid pointers#435
h2zero merged 2 commits into
masterfrom
bugfix/wl

Conversation

@h2zero

@h2zero h2zero commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Bug Fixes
    • Improved Bluetooth whitelist updates and removals for more reliable device management.
    • Improved scan shutdown and cleanup during host deinitialization.
    • Deferred scan-response timer setup until needed, reducing unnecessary resource usage.
    • Ensured pending scan devices and timers are safely cleared when scanning ends.
    • Prevented scan timeouts when timer setup fails.
    • Added clearer failure reporting when Bluetooth host shutdown cannot complete.

…terator

* fix: whiteListRemove use-after-free - stop iterating after erase + shrink

whiteListRemove erases the matched element (invalidating the iterator) and
shrink-to-fits m_whiteList (freeing the buffer the iterator points into),
then continues the loop on the dangling iterator. A layout-dependent
spurious re-match then calls erase() with a foreign iterator, and the
vector's internal element move writes across unrelated heap memory.

Observed on ESP32-C3 as intermittent heap corruption under whitelist churn
(multi_heap_free bad-head asserts with address bytes in the corrupted
header; a clobbered NimBLE host mutex tripping xQueueSemaphoreTake).
Verified fixed under CONFIG_HEAP_POISONING_COMPREHENSIVE plus periodic
heap_caps_check_integrity_all() sweeps.

whiteListAdd guards duplicates via onWhiteList(), so at most one element
can match - breaking out after the removal preserves semantics.

* fix: use m_whiteList.data() - operator[] on an empty vector is UB

After erasing the last whitelist entry, &m_whiteList[0] indexes an empty
vector before ble_gap_wl_set(..., 0). data() is well-defined for empty
vectors; same change applied to the whiteListAdd call site for consistency.
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cb6c0f32-bd11-4b31-a3d6-ad3cef53ad26

📥 Commits

Reviewing files that changed from the base of the PR and between 2fbcebe and ef100d6.

📒 Files selected for processing (3)
  • src/NimBLEDevice.cpp
  • src/NimBLEScan.cpp
  • src/NimBLEScan.h
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/NimBLEDevice.cpp
  • src/NimBLEScan.h
  • src/NimBLEScan.cpp

📝 Walkthrough

Walkthrough

The PR updates whitelist synchronization and removal handling. It adds lazy scan-response timer initialization, guarded cleanup, host-deinitialization handling, and failure reporting for nimble_port_stop(), arr.

Changes

Scan and whitelist lifecycle

Layer / File(s) Summary
Whitelist synchronization fixes
src/NimBLEDevice.cpp
Whitelist updates use m_whiteList.data(). Removal stops after the successful erase and buffer swap.
Scan-response timer lifecycle
src/NimBLEScan.h, src/NimBLEScan.cpp, src/NimBLEDevice.cpp
The callout initializes only when pending devices require a timer. Stop and deinitialization paths check the initialization flag. Host deinitialization clears pending devices and deinitializes the callout before host teardown.
Host stop failure handling
src/NimBLEDevice.cpp
deinit logs a nimble_port_stop() failure and returns false when the stop operation fails, arrr.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant NimBLEDevice
  participant NimBLEScan
  participant ScanResponseCallout
  participant NimBLEHost
  NimBLEDevice->>NimBLEScan: onHostDeinit()
  NimBLEScan->>NimBLEScan: clearWaitingList()
  NimBLEScan->>ScanResponseCallout: deinit()
  NimBLEDevice->>NimBLEHost: stop and deinitialize
  NimBLEDevice->>NimBLEDevice: log and return false if nimble_port_stop() fails
Loading

Possibly related PRs

Poem

Arr, the whitelist finds its proper data berth.
The scan timer wakes only when devices need its worth.
Pending entries clear before hosts depart.
Failed stops now report their part.
Safe callouts guard the chart.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the whitelist removal and scan-response timer crash fixes described in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 bugfix/wl

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

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/NimBLEScan.cpp`:
- Around line 699-702: Move the NimBLE scan host-deinitialization call from its
current pre-stop location into the successful `rc == 0` shutdown path,
immediately after `nimble_port_stop()` and before `nimble_port_deinit()`. Update
the flow around `NimBLEDevice::m_pScan->onHostDeinit()` so
`ble_npl_callout_deinit()` in `onHostDeinit()` cannot run while NimBLE task
callbacks remain queued.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c44d8930-28ae-459e-b3bc-1913c24e4c79

📥 Commits

Reviewing files that changed from the base of the PR and between 3413bf9 and 2fbcebe.

📒 Files selected for processing (3)
  • src/NimBLEDevice.cpp
  • src/NimBLEScan.cpp
  • src/NimBLEScan.h

Comment thread src/NimBLEScan.cpp
Fixes a crash when the stack is reinitialized without clearing all data on deinit then starting scanning.
@h2zero
h2zero merged commit 782af27 into master Aug 1, 2026
66 checks passed
@h2zero
h2zero deleted the bugfix/wl branch August 1, 2026 22:16
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