1
0
mirror of https://github.com/esp8266/Arduino.git synced 2026-10-23 19:08:55 +03:00

Mock - clean up in UdpContext destructor (#9312)

* Fix possible crash in UdpContext host mocking.

I saw this crash in UdpContext.h happen after some hours of regular NTP requests....

```
[17:38:51] ADE:  voltage spike: phase A, factor=0.81, cycles=1
(mock) ClientContext::connect: ::connect(): Connection refused
(mock) ClientContext::connect: ::connect(): Connection refused
(mock) ClientContext::connect: ::connect(): Connection refused
(mock) ClientContext::connect: ::connect(): Connection refused
[17:41:14] ADE:  voltage spike: phase A, factor=0.86, cycles=2
(mock) ClientContext::connect: ::connect(): Connection refused
(mock) ClientContext::connect: ::connect(): Connection refused
(mock) ClientContext::connect: ::connect(): Connection refused
(mock) ClientContext::connect: ::connect(): Connection refused
[17:43:49] ADE:  voltage spike: phase B, factor=1.12, cycles=3
(mock) ClientContext::connect: ::connect(): Connection refused
(mock) =====> UdpServer port: 2390 <=====
[17:44:31] NTP:  waiting for response from '81.169.233.252' timed out

Program received signal SIGSEGV, Segmentation fault.
0x000055555556848c in std::_Function_base::_M_empty() const ()
(gdb) where
#0  0x000055555556848c in std::_Function_base::_M_empty() const ()
#1  0x00005555555685be in std::function<void ()>::operator bool() const ()
#2  0x00005555555684b8 in UdpContext::mock_cb() ()
#3  0x00005555555683af in check_incoming_udp() ()
#4  0x0000555555567fa6 in main ()
```

I tracked it down to UdpContext::mock_cb() which is calling a std::function callback that's been destroyed thus used-after-free. I believe  what happens is:
  1. UdpContext::unref() calls delete this when refcount hits 0 (line 56)
  2. The destructor (~UdpContext(), line 47) is empty — it never calls register_udp(_sock, nullptr) to remove itself from the global udps map
  3. check_incoming_udp() iterates udps, finds the dangling pointer, calls mock_cb() on freed memory
  4. _on_rx (a destroyed std::function) → segfault in _M_empty()

The disconnect() method already does the right thing (lines 78-84: closes socket + unregisters), but it's never called before the object is destroyed via  unref().

The fix is to make the destructor clean up properly.

I tested intensely, no crashes since.

* Format destructor for UdpContext for clarity

Fixes code-style CI.
This commit is contained in:
Clemens Kirchgatterer
2026-03-23 10:22:38 +01:00
committed by GitHub
parent 7b0ac41694
commit f946290ea9

View File

@@ -44,7 +44,10 @@ public:
_sock = mockUDPSocket();
}
~UdpContext() { }
~UdpContext()
{
disconnect();
}
void ref()
{