0

I'm doing a project using an ESP32 TTGO with LoRa, the Max485 and a WELLPRO ADAM 8082 for Modbus communication. I'm trying to use the ESP32 as a master to and the ADAM as a slave. I'm also using Node-RED to send the input signals (reading the digital inputs on the ADAM or sending signals to the digital outputs). Whenever I send a signal there's no problem, the ADAM receives it correctly and sends the answer. But when my ESP32 receives the answer, I get the following error:

Stack smashing protect failure!

abort() was called at PC 0x400dc860 on core 1

I tried debugging my program and the error happens when my program comes back from the function that has my reading modbus loop. I'm pretty new to Arduino, so I don't really understand what could be causing this stack overflow.

Here's my code.

My global variables:

unsigned char ucSt[N_MAX];
int delayTime;

HardwareSerial modbusData(2);

WiFiClientSecure espClient;
PubSubClient client(espClient);
boolean bWifiConnected = false;

const byte button = PRG_BUTTON;

Modbus reading with loop:

void vReadingModBus()
{
  int i, nCmpt = 0;
  unsigned int uiCRC;

  while (modbusData.available() > 0)
  {
    Serial.print("nCmpt: ");
    Serial.println(nCmpt);
    ucSt[nCmpt] = (unsigned char)modbusData.read();
    nCmpt++;
    delay(delayTime - 2);
  }
  if (nCmpt)
  {
    Serial.print("He llegit aquests ");
    Serial.print(nCmpt);
    Serial.println(" bytes: ");
    char szResposta[N_MAX] = "", szByte[3];
    for (i = 0; i < nCmpt; i++)
    {
      sprintf(szByte, "%02X", ucSt[i]);
      strcat(szResposta, szByte);
      Serial.print(ucSt[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
    client.publish(TEMA_RESPOSTA_MODBUS, szResposta);
    uiCRC = uiModRTU_CRC(ucSt, nCmpt - 2);
    if ((byte)(uiCRC >> 8) == ucSt[nCmpt - 1] && (byte)(uiCRC & 0xFF) == ucSt[nCmpt - 2])
    {
      Serial.println("Trama amb CRC correcte");
    }
    else
    {
      Serial.println("Trama amb CRC incorrecte");
    }
  }
  nCmpt = 0;
}

Modbus transmission:

void vModbusTx(unsigned char *uc, int nLen)
{
  int i;

  Serial.print("Enviat: ");
  for (i = 0; i < nLen; i++)
  {
    Serial.print(uc[i], HEX);
    Serial.print(" ");
  }
  Serial.println();

  vModeTxRxRS485(RS485Transmit);
  delay(1);
  for (i = 0; i < nLen; i++)
  {
    modbusData.write(uc[i]);
  }
  delay(delayTime);

  vModeTxRxRS485(RS485Receive);
}

My setup:

void setup() {
  Serial.begin(115200);    // U0_RXD:GPIO3, U0_TXD:GPIO1 (UART0)
  modbusData.begin(9600); // U2_RXD:GPIO16, U2_TXD:GPIO17 (UART2)

  pinMode(PRG_BUTTON, INPUT_PULLUP);
  pinMode(GPIO_R2, INPUT); // 39
  pinMode(SSerialTxControl, OUTPUT); // hardwired to GPIO_R2
  pinMode(LED, OUTPUT);

  vModeTxRxRS485(RS485Receive); // RS485Receive is a 0, and vModeTxRxRS485 controls the DE/RE bits for the Max485

  delayTime = 0;

  //Wire.begin(I2C_SCL_OLED);

  delay(1000); // give me time to bring up serial monitor
}

My loop:

void loop() {
  boolean bButtonState = !digitalRead(button);
  static boolean bLastButtonState = bButtonState;

  // MODBUS READING LOOP
  vReadingModBus();

  if (!client.connected())
  {
    reconnect();
  }

  // BUTTON STATE CHECK
  if (bButtonState != bLastButtonState)
  {
    bLastButtonState = bButtonState;
    vDelayESP(50);
    if (!bButtonState)
      client.publish(TEMA_PUBLICA_ESTAT_BOTO, "UNPRESSED");
    else
      client.publish(TEMA_PUBLICA_ESTAT_BOTO, "PRESSED");
  }

  client.loop();
}

And finally here's an example of my program running and giving the error mentioned:

Connecting to WiFi network
Waiting for WIFI connection...
..............................................
Attempting MQTTS connection...connected
Message arrived [/clot/dam/biel/esp32/escriuModbus] 010F000000080111
Petició a ModBus:
010F000000080111
Mida: 8
ucSt[0] = 1
ucSt[1] = F
ucSt[2] = 0
ucSt[3] = 0
ucSt[4] = 0
ucSt[5] = 8
ucSt[6] = 1
ucSt[7] = 11
Enviat: 1 F 0 0 0 8 1 11 3E 99 
He llegit aquests 8 bytes: 
1 F 0 0 0 8 54 D 
Trama amb CRC correcte

Stack smashing protect failure!

abort() was called at PC 0x400dc7d8 on core 1

Backtrace: 0x4008c800:0x3ffb1ef0 0x4008ca31:0x3ffb1f10 0x400dc7d8:0x3ffb1f30 0x400d1eed:0x3ffb1f50 0x400d23c0:0x3ffb1f90 0x400d513d:0x3ffb1fb0 0x4008879d:0x3ffb1fd0

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:928
ho 0 tail 12 room 4
load:0x40078000,len:8424
ho 0 tail 12 room 4
load:0x40080400,len:5868
entry 0x4008069c

1

tl;dr: The message probably means your function is overwriting its array:

A stack overflow is caused by a stack that grows downward into the allocated heap space, either causing damage to data within the heap, or code using that heap space causing damage to the contents of the stack.

But "stack smashing" refers to damage caused by function code writing past the bounds of an automatic local variable and damaging the stack contents, typically including the function's return address.

[Feel free to skip rather long explanation:]

A function's stack-frame begins with the return address - the address following the instruction that calls the function, i.e., the address of the next instruction to be executed after the function returns. Then, building downwards, the call parameters are put on the stack and become local variables. Then any variables allocated during the function execution are allocated, still building downward.

Assume one of those allocated variables is an array. Its zero-th element is in the lowest address of the allocated space, and subsequent elements are at successively higher addresses. If I start writing into the array, and continue past its length, I'll eventually overwrite other automatic locals, my parameters, and and my return address. Then, when the function tries to return, instead of jumping to the code that called the function, the MCU uses the damaged return address and jumps to ... ????

To catch this error, the compiler can insert code that 1) allocates and writes a "canary" - a known value - just after the return address, and 2), checks the canary for damage just before the function returns. If the canary has been altered, you get the message you saw, because it's likely that the return address will have been altered also. But regardless, the canary isn't part of your code and isn't accessible to it. Thus, it detects writing-out-of-bounds errors.

[End of wordy explanation]

Check the code in your function 'void vReadingModBus()' - my money is on the loop that writes into szResposta[]:

  char szResposta[N_MAX] = "", szByte[3];
    for (i = 0; i < nCmpt; i++)
    {
      sprintf(szByte, "%02X", ucSt[i]);
      strcat(szResposta, szByte);
      Serial.print(ucSt[i], HEX);
      Serial.print(" ");
    }

Update:

If I understood correctly, it means szResposta must be overwriting the function's return address? How should I avoid this?

The short answer is make your array big enough for what you're going to put in it. But that's probably not a satisfying answer though, so let's take a closer look. I'm not sure exactly what your intent is in that loop, but since you print the strcat() result at every iteration and you don't seem to use szResposta after that, perhaps you meant to call strcpy() (replace the contents of the array) instead of strcat() (extend the contents of the array). If so, strcat() would quite likely write past the array bounds.

  • Thank you so much for this fantastic explanation! It certainly was the loop. The line giving the error is strcat(szResposta, szByte). If I understood correctly, it means szResposta must be overwriting the function's return address? How should I avoid this? Thank you, again! – Biel May 19 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.