From b91b3ca96f13d59e6fc7cf023c83ef5100f5132b Mon Sep 17 00:00:00 2001 From: MaPaLo76 <72209721+MaPaLo76@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:05:09 +0100 Subject: [PATCH] fix(mqtt): Netzwerk-Objekte per new auf Core 0 anlegen - Heap-Korruption behoben - WiFiClient, WiFiClientSecure, PubSubClient als Pointer deklariert (nullptr init) - Objekte werden erst in _taskLoop() auf Core 0 per 'new' erstellt - mbedtls bindet Heap-Allokationen an den erstellenden Core/Task -> Anlegen auf Core 1 (globaler Konstruktor) + Nutzung auf Core 0 = Heap-Korruption -> Fix: Anlegen UND Nutzung ausschliesslich auf Core 0 - isConnected(), printToSerial(): Null-Checks ergaenzt --- include/mqtt_client.h | 10 +++++--- src/mqtt_client.cpp | 59 +++++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/include/mqtt_client.h b/include/mqtt_client.h index 6a3c2b5..5483ea0 100644 --- a/include/mqtt_client.h +++ b/include/mqtt_client.h @@ -52,9 +52,13 @@ public: void printToSerial(); private: - WiFiClient _wifiClient; - WiFiClientSecure _secureClient; // fuer TLS (Port 8883) - PubSubClient _client; + // WICHTIG: Diese Objekte werden als nullptr initialisiert und erst in + // _taskLoop() auf Core 0 per 'new' angelegt. mbedtls/WiFiClientSecure + // bindet Heap-Kontexte an den erstellenden Task/Core – daher KEIN + // Anlegen im globalen Konstruktor (Core 1)! + WiFiClient* _wifiClient; + WiFiClientSecure* _secureClient; + PubSubClient* _client; uint32_t _lastReconnectMs; uint32_t _lastHeartbeatMs; diff --git a/src/mqtt_client.cpp b/src/mqtt_client.cpp index 18c0176..00f773e 100644 --- a/src/mqtt_client.cpp +++ b/src/mqtt_client.cpp @@ -16,7 +16,9 @@ MqttClient mqttClient; // Konstruktor // -------------------------------------------------------------------------- MqttClient::MqttClient() - : _client(_wifiClient) + : _wifiClient(nullptr) + , _secureClient(nullptr) + , _client(nullptr) , _lastReconnectMs(0) , _lastHeartbeatMs(0) , _taskHandle(nullptr) @@ -80,7 +82,7 @@ void MqttClient::publishSession(int lastSessionSec, int gratisSec) { // _doPublishSession() - eigentlicher Publish, wird aus MQTT-Task aufgerufen // -------------------------------------------------------------------------- void MqttClient::_doPublishSession(int lastSessionSec, int gratisSec) { - if (!_client.connected()) { + if (!_client->connected()) { LOG_E("MQTT", "_doPublishSession: nicht verbunden, uebersprungen"); return; } @@ -106,7 +108,7 @@ void MqttClient::_doPublishSession(int lastSessionSec, int gratisSec) { char buf[128]; serializeJson(doc, buf, sizeof(buf)); - bool ok = _client.publish(MQTT_TOPIC_SESSION, buf, /*retained=*/false); + bool ok = _client->publish(MQTT_TOPIC_SESSION, buf, /*retained=*/false); LOG_I("MQTT", "publishSession: %s -> %s", buf, ok ? "OK" : "FEHLER"); } @@ -125,7 +127,7 @@ void MqttClient::publishHeartbeat() { char buf[220]; serializeJson(doc, buf, sizeof(buf)); - bool ok = _client.publish(MQTT_TOPIC_STATUS, buf, /*retained=*/true); + bool ok = _client->publish(MQTT_TOPIC_STATUS, buf, /*retained=*/true); LOG_I("MQTT", "Heartbeat: %s -> %s", buf, ok ? "OK" : "FEHLER"); } @@ -133,38 +135,34 @@ void MqttClient::publishHeartbeat() { // reconnect() - Verbindungsaufbau, non-blocking // -------------------------------------------------------------------------- bool MqttClient::reconnect() { - if (_client.connected()) return true; + if (_client->connected()) return true; const auto& cfg = settings.get(); const char* user = cfg.mqttUser[0] != '\0' ? cfg.mqttUser : nullptr; const char* pass = cfg.mqttPassword[0] != '\0' ? cfg.mqttPassword : nullptr; - // Offline-LWT (Last Will and Testament) const char* lwtPayload = "{\"online\":false}"; LOG_I("MQTT", "Verbinde als '%s'...", _clientId); - // TLS-Handshake kann 2-15 s dauern. Laeuft auf Core 0 (MQTT-Task), - // blockiert Core 1 (loop/LaserTracker/Display) nicht mehr. bool ok; if (user && pass) { - ok = _client.connect(_clientId, user, pass, - MQTT_TOPIC_STATUS, 0, true, lwtPayload); + ok = _client->connect(_clientId, user, pass, + MQTT_TOPIC_STATUS, 0, true, lwtPayload); } else { - ok = _client.connect(_clientId, - nullptr, nullptr, - MQTT_TOPIC_STATUS, 0, true, lwtPayload); + ok = _client->connect(_clientId, + nullptr, nullptr, + MQTT_TOPIC_STATUS, 0, true, lwtPayload); } if (ok) { LOG_I("MQTT", "Verbunden!"); - _client.subscribe(MQTT_TOPIC_RESET); + _client->subscribe(MQTT_TOPIC_RESET); LOG_I("MQTT", "Abonniert: %s", MQTT_TOPIC_RESET); - // Sofortigen Heartbeat senden publishHeartbeat(); _lastHeartbeatMs = millis(); } else { - LOG_E("MQTT", "Verbindung fehlgeschlagen, rc=%d", _client.state()); + LOG_E("MQTT", "Verbindung fehlgeschlagen, rc=%d", _client->state()); } return ok; @@ -188,17 +186,22 @@ void MqttClient::_taskLoop() { const char* broker = cfg.mqttBroker[0] != '\0' ? cfg.mqttBroker : DEFAULT_MQTT_BROKER; uint16_t port = cfg.mqttPort > 0 ? cfg.mqttPort : DEFAULT_MQTT_PORT; + // Netzwerk-Objekte auf Core 0 anlegen (mbedtls/WiFiClientSecure bindet + // Heap-Kontexte an den erstellenden Task/Core -> kein Cross-Core-Zugriff). + _wifiClient = new WiFiClient(); + _secureClient = new WiFiClientSecure(); + if (port == 8883) { - _secureClient.setInsecure(); - _client.setClient(_secureClient); + _secureClient->setInsecure(); + _client = new PubSubClient(*_secureClient); LOG_I("MQTT", "TLS aktiv (setInsecure, Core 0)"); } else { - _client.setClient(_wifiClient); + _client = new PubSubClient(*_wifiClient); } - _client.setServer(broker, port); - _client.setCallback(MqttClient::onMessage); - _client.setKeepAlive(60); - _client.setBufferSize(512); + _client->setServer(broker, port); + _client->setCallback(MqttClient::onMessage); + _client->setKeepAlive(60); + _client->setBufferSize(512); for (;;) { // Kein WiFi: warten @@ -208,7 +211,7 @@ void MqttClient::_taskLoop() { } // Nicht verbunden: Reconnect-Intervall abwarten, dann versuchen - if (!_client.connected()) { + if (!_client->connected()) { uint32_t now = millis(); if (now - _lastReconnectMs >= MQTT_RECONNECT_MS) { _lastReconnectMs = now; @@ -219,7 +222,7 @@ void MqttClient::_taskLoop() { } // PubSubClient-interne Verarbeitung (eingehende Nachrichten) - _client.loop(); + _client->loop(); // Pending Session-Publish (von Core 1 via volatile Flag gesetzt) if (_pendingSession) { @@ -299,7 +302,7 @@ void MqttClient::onMessage(const char* topic, byte* payload, unsigned int length // isConnected() // -------------------------------------------------------------------------- bool MqttClient::isConnected() { - return _client.connected(); + return _client != nullptr && _client->connected(); } // -------------------------------------------------------------------------- @@ -311,7 +314,7 @@ void MqttClient::printToSerial() { LOG_I("MQTT", " Broker : %s", cfg.mqttBroker[0] ? cfg.mqttBroker : DEFAULT_MQTT_BROKER); LOG_I("MQTT", " Port : %u", cfg.mqttPort > 0 ? cfg.mqttPort : DEFAULT_MQTT_PORT); LOG_I("MQTT", " ClientID : %s", _clientId[0] ? _clientId : MQTT_CLIENT_ID); - LOG_I("MQTT", " Verbunden: %s", _client.connected() ? "JA" : "NEIN"); - LOG_I("MQTT", " rc : %d", _client.state()); + LOG_I("MQTT", " Verbunden: %s", (_client && _client->connected()) ? "JA" : "NEIN"); + LOG_I("MQTT", " rc : %d", _client ? _client->state() : -1); LOG_I("MQTT", "=================="); } \ No newline at end of file