Avoiding Buffer Overflows with the MQTT PubSub Client

The MQTT PubSub client callback passes the payload parameter as a pointer to a byte array and not a pointer to a char array - this is due to the content of the publish payload being application specific. In other words, from the point of view of the protocol, the payload can be a string, a file, and image, etc. By contrast, the topic parameter is indeed expected to be a string, hence the buffer pointer char *topic among the function parameters.

The result is that just casting the payload byte parameter to a const char * and converting to a String type will not work because the ending null character will be missing. Given the published payload:

{"action":"subscribed"}

handled by the PubSub callback:

void mqttCallback(char *topic, byte *payload, unsigned int length) {
  String msgTopic = String(topic);
  String msgPayload = (const char *) payload;
  //...

will result in the msgPayload string containing garbage:

{"action":"subscribed"}d}"

Perhaps a simpler way of dealing with the payload parameter, in case the expected content is a string, would be to create a null-terminated character array:

void mqttCallback(char *topic, byte *payload, unsigned int length) {
  String msgTopic = String(topic);
  // payload is not null terminated and casting will not work
  char msgPayload[length + 1];
  snprintf(msgPayload, length + 1, "%s", payload);
  Serial.println("Message received on topic: " + String(topic) + " with payload: " + String(msgPayload));
  // ...

Now String(msgPayload) will display the string properly. Unfortunately, a lot of available examples incorrectly convert the payload parameter resulting in small yet ever-increasing memory corruption over time which leads to stability issues with the Arduino device.

Recover Bricked Arduino

Connect an output pin to ground (ie: D3 on WeMoS mini) and plug in the USB cable to flash a new sketch. Disconnect the cable after flashing and reset the board.