Skip to content

EspWebSocketClient::Drop still panics: esp_websocket_client_destroy unwrap #653

Description

@fuk-yu

PR #648 fixed the esp_websocket_client_close unwrap in Drop, but esp_websocket_client_destroy still calls .unwrap():

  impl Drop for EspWebSocketClient<'_> {
      fn drop(&mut self) {
          if let Err(e) = esp!(unsafe { esp_websocket_client_close(self.handle, self.timeout) }) {
              log::warn!("WebSocket close failed during drop: {e:?}");
          }
          esp!(unsafe { esp_websocket_client_destroy(self.handle) }).unwrap(); // can still panic
      }
  }

Why this is a problem

  1. Drop must not panic. On ESP-IDF targets using panic = "abort", any panic in Drop aborts the entire application — there is no unwinding to catch it. A
    Drop impl should be infallible.
  2. The new_raw construction order triggers this. The client struct is constructed before esp_websocket_client_start() is called. When start() fails (e.g.,
    server unreachable), the ? operator returns Err, dropping the already-constructed client. Drop then runs on a client whose transport was never established.
  3. esp_websocket_client_destroy can return errors. While it typically returns ESP_OK, the ESP-IDF documentation does not guarantee this. Future ESP-IDF
    versions or edge cases (e.g., double-free, corrupted handle after a failed start) could cause it to fail.

Suggested fix

Apply the same pattern as close — or simpler, just ignore errors from both cleanup calls:

  impl Drop for EspWebSocketClient<'_> {
      fn drop(&mut self) {
          let _ = esp!(unsafe { esp_websocket_client_close(self.handle, self.timeout) });
          let _ = esp!(unsafe { esp_websocket_client_destroy(self.handle) });
      }
  }

Reproduction

  1. Configure EspWebSocketClient with disable_auto_reconnect: true pointing at a non-existent server
  2. Call EspWebSocketClient::new() — the TCP connection fails asynchronously
  3. The client is dropped (either from new_raw error path or after detecting the failure)
  4. Result: abort() was called — application crashes

Environment

  • ESP32-P4, esp-idf-svc 0.52.1, ESP-IDF v5.4.3 / v5.5.4
  • panic = "abort" (default for ESP-IDF targets)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status
    Review

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions