简体   繁体   中英

WifiClient issue - must be a basic C/C++ problem regarding local vs. global variables

In the code below, I am getting crashes when doing mqtt.publish() but this only happens if wificlient is a local variable - the issue goes away if wificlient is a global variable.

I don't think there's much of a need to know the underlying libraries.

There must be a subtlety regarding pointers / garbage collection or what not that causes this. I've been doing C# for years, have much less experience with C++.

#include <PubSubClient.h>
#include <WiFiClient.h>

void mqttSubs(char* topic, byte* payload, unsigned int length) {}   


// if this line is moved inside setup() then the call to publish will crash
WiFiClient wifiClientGlobal;
PubSubClient mqttClient;

void setup() {
  //WiFiClient wifiClientGlobal;
  mqttClient = PubSubClient(mqttServer, mqttPort, mqttSubs, wifiClientGlobal);
  mqttClient.connect("ESP8266Client", mqttUser, mqttPassword );
}

void loop() {
  mqttClient.publish("repro/global", "sending message");
}

Can anyone shed a light on this?

There's not much sublety, just (imo) bad documentation and suboptiomal API on PubSubClient.

The PubSubClient constructor takes a reference to the client.

PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);

And then takes a pointer to it to store as a member.

This means that it expects the Client instance it takes a reference to to outlive the PubSubClient instance.

There's no garbage collection taking place. It's just that if you declare an object with automatic storage duration then it will be destroyed when it goes out of scope.

So the reason is essentially this:

struct B{
    int num;
};

struct A{
    A(B& param){
        m_b = &param;
    }
    B* m_b;
};

A obj;

setup()
{
    B b;
    obj = A(b); 
    //after this function ends b is considered destroyed
}

loop()
{
    //the following line accesses a member of the already destroyed object
    print(obj.m_b->num);
}

This test case exhibits essentially the same "use after free" as your code (it probably won't crash but it does contain the same undefined behavior).

The PubSubClient taking a reference to the client and storing the pointer for later use is a bad pattern in my opinion. It should take a pointer to the client to make it more apparent that this is what happens.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM