Skip to content

Fix dangling callback reference and sim ESP-NOW channel reliability#6

Merged
peterus merged 2 commits intonew_channel_managementfrom
copilot/sub-pr-5
Mar 13, 2026
Merged

Fix dangling callback reference and sim ESP-NOW channel reliability#6
peterus merged 2 commits intonew_channel_managementfrom
copilot/sub-pr-5

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 13, 2026

Two bugs introduced in the channel discovery PR: a dangling reference UAF in the receiver's discovery callback, and a broken sim ESP-NOW transport that only delivered packets to one process per port.

ReceiverApp: RAII guard for onDiscoveryResponse callback

runChannelDiscovery() registered a callback capturing a reference to a stack-local ChannelScanner. The callback outlived the scanner, creating a UAF on the next discovery cycle.

Fixed with a local RAII guard that clears the callback at every exit point (C++ destruction order guarantees the guard runs before the scanner):

_radio.onDiscoveryResponse([&scanner](...) { scanner.onDiscoveryResponse(...); });
struct DiscoveryResponseGuard {
    ReceiverRadioLink &radio;
    ~DiscoveryResponseGuard() { radio.onDiscoveryResponse(nullptr); }
} cbGuard{_radio};

sim_espnow: UDP multicast + thread-safe channel switching

  • Unicast → multicast per channel (239.0.0.<ch>:<port>): SO_REUSEPORT unicast delivers to only one socket under kernel load-balancing, breaking multi-process sim scenarios. Each process now joins the multicast group via IP_ADD_MEMBERSHIP on loopback; esp_now_send() targets the group address.
  • Thread-safe rebind: sim_set_wifi_channel() previously closed/reopened the socket while recvLoop was live. Now stops the thread with pthread_join() (error-checked) before touching the socket, then restarts it.

cmd_io: Fix incorrect cppcheck suppression

txCmdModule had // cppcheck-suppress constParameterCallback but the actual warning is constParameterPointer. Corrected to match the emitted diagnostic.


💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

…an-out, thread-safe channel switch

Co-authored-by: peterus <1764325+peterus@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 13, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • api.registry.nm1.platformio.org
    • Triggering command: /home/REDACTED/.local/bin/pio /home/REDACTED/.local/bin/pio test -e native (dns block)
    • Triggering command: /home/REDACTED/.local/bin/pio /home/REDACTED/.local/bin/pio run -e sim_rx (dns block)
  • api.registry.platformio.org
    • Triggering command: /home/REDACTED/.local/bin/pio /home/REDACTED/.local/bin/pio test -e native (dns block)
    • Triggering command: /home/REDACTED/.local/bin/pio /home/REDACTED/.local/bin/pio run -e sim_rx (dns block)
  • collector.platformio.org
    • Triggering command: /home/REDACTED/.local/bin/pio /home/REDACTED/.local/bin/pio test -e native (dns block)
    • Triggering command: /home/REDACTED/.local/bin/pio /home/REDACTED/.local/bin/pio run -e sim_rx (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title [WIP] Add new channel management system for OpenDriveHub Fix dangling callback reference and sim ESP-NOW channel reliability Mar 13, 2026
Copilot AI requested a review from peterus March 13, 2026 19:39
@peterus peterus marked this pull request as ready for review March 13, 2026 19:43
Copilot AI review requested due to automatic review settings March 13, 2026 19:43
@peterus peterus merged commit 5d005f0 into new_channel_management Mar 13, 2026
@peterus peterus deleted the copilot/sub-pr-5 branch March 13, 2026 19:43
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Dieses PR behebt zwei Regressionen aus dem Channel-Discovery-Feature: einen Use-after-free durch einen langlebigen Discovery-Callback im Receiver sowie unzuverlässiges Paket-Fanout in der nativen ESP-NOW-Simulation durch Wechsel von UDP-Unicast auf Multicast.

Changes:

  • Receiver: RAII-Guard, der den onDiscoveryResponse-Callback beim Verlassen von runChannelDiscovery() zuverlässig zurücksetzt (verhindert dangling reference auf stack-lokalen ChannelScanner).
  • Simulation: ESP-NOW-Transport auf UDP-Multicast pro Kanal umgestellt und Channel-Switch so angepasst, dass der Receive-Thread vor Rebind gestoppt/restarted wird.
  • Transmitter Shell: cppcheck-Suppression-Tag auf die tatsächlich gemeldete Warnung angepasst.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
firmware/src/transmitter/shell/cmd_io.cpp Korrigiert cppcheck-Suppression auf den passenden Warnungsnamen.
firmware/src/receiver/ReceiverApp.cpp Fügt Scope-Guard hinzu, der Discovery-Callback beim Return löscht und so UAF verhindert.
firmware/sim/src/sim_espnow.cpp Wechselt auf Multicast pro Kanal und implementiert Thread-Stop/Restart beim Channel-Wechsel.

Comment on lines +256 to +262
const bool wasRunning = s_running;
if (wasRunning) {
s_running = false;
if (pthread_join(s_recvThread, nullptr) != 0) {
perror("[SIM] pthread_join failed during channel switch");
}
}
Comment on lines 264 to +273
s_currentChannel = channel;
if (s_running) {

if (wasRunning) {
rebindSocket();
if (s_sock >= 0) {
s_running = true;
pthread_create(&s_recvThread, nullptr, recvLoop, nullptr);
} else {
fprintf(stderr, "[SIM] rebindSocket failed during channel switch to %u\n", channel);
}
Comment on lines +74 to +79
/// Returns the multicast group IPv4 address for the given channel in host
/// byte order: channel ch → 239.0.0.ch.
/// Valid input channels are 1, 6, and 11 (see channel::kCandidateChannels).
static inline uint32_t channelMulticastIp(uint8_t ch) {
return (239u << 24) | static_cast<uint32_t>(ch);
}
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.

3 participants