how to fix stack smashing protect failure in ESP32

Hi, I am new in using ESP32. I have project that uses ESP32 Dev Module to get fingerprint template from the fingerprint module R307 but I keep getting error "stack smashing protect failure" while I print the template. How can I fix the error.

#include <Adafruit_Fingerprint.h>

HardwareSerial mySerial(2);
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
uint8_t id = 1;
int addr = 0;
byte value;
String fingerTemplate = "";
String fingerTemplates = "";


uint8_t getFingerprintID() {
  uint8_t p = finger.getImage();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image taken");
      break;
    case FINGERPRINT_NOFINGER:
      Serial.println("No finger detected");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    case FINGERPRINT_IMAGEFAIL:
      Serial.println("Imaging error");
      return p;
    default:
      Serial.println("Unknown error");
      return p;
  }

  // OK success!

  p = finger.image2Tz();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image converted");
      break;
    case FINGERPRINT_IMAGEMESS:
      Serial.println("Image too messy");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    case FINGERPRINT_FEATUREFAIL:
      Serial.println("Could not find fingerprint features");
      return p;
    case FINGERPRINT_INVALIDIMAGE:
      Serial.println("Could not find fingerprint features");
      return p;
    default:
      Serial.println("Unknown error");
      return p;
  }
  id = 1;
 p = finger.storeModel(id);
  if (p == FINGERPRINT_OK) {
    Serial.println("Stored!");
    return id;
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    Serial.println("Communication error");
    return p;
  } else if (p == FINGERPRINT_BADLOCATION) {
    Serial.println("Could not store in that location");
    return p;
  } else if (p == FINGERPRINT_FLASHERR) {
    Serial.println("Error writing to flash");
    return p;
  } else {
    Serial.println("Unknown error");
    return p;
  } 
}

uint8_t downloadFingerprintTemplate(uint8_t id)
{
  Serial.println("------------------------------------");
  Serial.print("Attempting to load #"); Serial.println(id);
  uint8_t p = finger.loadModel(id);
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" loaded");
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

  // OK success!

   p = finger.getModel();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.println(" transferring:");
      break;
   default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }


  uint8_t templateBuffer[256];
  memset(templateBuffer, 0xff, 256);  //zero out template buffer
  int index=0;
  uint32_t starttime = millis();
  while ((index < 256) && ((millis() - starttime) < 1000))
  {
    if (mySerial.available())
    {
      templateBuffer[index] = mySerial.read();
      index++;
    }
  }
  
  Serial.print(index); Serial.println(" bytes read");
  Serial.print(" <");
  
  //dump entire templateBuffer.  This prints out 16 lines of 16 bytes
  for (int count= 0; count < 16; count++)
  {
    for (int i = 0; i < 16; i++)
    {
      fingerTemplate = String(templateBuffer[count*16+i], HEX);
      fingerTemplate.toUpperCase();
      Serial.print(fingerTemplate);
      }
  }
  Serial.print(">");
  Serial.println();
  
}

uint8_t deleteFingerprint(uint8_t id) {
  uint8_t p = -1;
  
  p = finger.deleteModel(id);

  if (p == FINGERPRINT_OK) {
    Serial.println("Deleted!");
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    Serial.println("Communication error");
    return p;
  } else if (p == FINGERPRINT_BADLOCATION) {
    Serial.println("Could not delete in that location");
    return p;
  } else if (p == FINGERPRINT_FLASHERR) {
    Serial.println("Error writing to flash");
    return p;
  } else {
    Serial.print("Unknown error: 0x"); Serial.println(p, HEX);
    return p;
  }   
}

void setup()  
{
  Serial.begin(9600);
  while (!Serial);  // For Yun/Leo/Micro/Zero/...
  delay(100);
  Serial.println("\n\nAdafruit finger detect test");

  // set the data rate for the sensor serial port
  finger.begin(57600);
  
  if (finger.verifyPassword()) {
    Serial.println("Found fingerprint sensor!");
  } else {
    Serial.println("Did not find fingerprint sensor :(");
    while (1) { delay(1); }
  }

  finger.getTemplateCount();
  Serial.print("Sensor contains "); Serial.print(finger.templateCount); Serial.println(" templates");
  Serial.println("Waiting for valid finger...");
}

void loop()                     // run over and over again
{
  id = getFingerprintID();
  Serial.println(id);
  while (id == 1 ){
  delay(50);
  downloadFingerprintTemplate(id);
//  deleteFingerprint(id);
  break;
  }
  delay(50);            //don't ned to run this at full speed.
//   
}

The error is:

Attempting to load #1
Template 1 loaded
Template transferring:
256 bytes read

Stack smashing protect failure!

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

Backtrace: 0x4008b560:0x3ffb1ea0 0x4008b78d:0x3ffb1ec0 0x400d51dc:0x3ffb1ee0 0x400d11c7:0x3ffb1f00 0x400d0c1d:0x3ffb1f70 0x400d0f5b:0xff981925

Rebooting...

Please modify your post so the sketch is within </. code-tags

uint8_t downloadFingerprintTemplate(uint8_t id)
{
  Serial.println("------------------------------------");
  Serial.print("Attempting to load #"); Serial.println(id);
  uint8_t p = finger.loadModel(id);
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" loaded");
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

  // OK success!

   p = finger.getModel();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.println(" transferring:");
      break;
   default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }


  uint8_t templateBuffer[256];
  memset(templateBuffer, 0xff, 256);  //zero out template buffer
  int index=0;
  uint32_t starttime = millis();
  while ((index < 256) && ((millis() - starttime) < 1000))
  {
    if (mySerial.available())
    {
      templateBuffer[index] = mySerial.read();
      index++;
    }
  }
 
  Serial.print(index); Serial.println(" bytes read");
  Serial.print(" <");
 
  //dump entire templateBuffer.  This prints out 16 lines of 16 bytes
  for (int count= 0; count < 16; count++)
  {
    for (int i = 0; i < 16; i++)
    {
      fingerTemplate = String(templateBuffer[count*16+i], HEX);
      fingerTemplate.toUpperCase();
      Serial.print(fingerTemplate);
      }
  }
  Serial.print(">");
  Serial.println();
 
}

the error occurs at the end of this function, and actually i am puzzled as to why it compiles, but anyway, it is not a 'void' function there fore at the end of it, there should be a return with a value, now in this case there is no return at all (at least not preceding the closing brace) add return value; i suspect this is what is wrong, a request to an empty stack.

Thank you for the reply, I am new at this forum but I edited the code.

THANKS, I changed it to a void but the result is the same.

void downloadFingerprintTemplate(uint8_t id)
{
  Serial.println("------------------------------------");
  Serial.print("Attempting to load #"); Serial.println(id);
  uint8_t p = finger.loadModel(id);
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" loaded");
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
    default:
      Serial.print("Unknown error "); Serial.println(p);
  }

  // OK success!

   p = finger.getModel();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.println(" transferring:");
      break;
   default:
      Serial.print("Unknown error "); Serial.println(p);
  }


  uint8_t templateBuffer[256];
  memset(templateBuffer, 0xff, 256);  //zero out template buffer
  int index=0;
  uint32_t starttime = millis();
  while ((index < 256) && ((millis() - starttime) < 1000))
  {
    if (mySerial.available())
    {
      templateBuffer[index] = mySerial.read();
      index++;
    }
  }
  
  Serial.print(index); Serial.println(" bytes read");
  Serial.print("<");
  
  //dump entire templateBuffer.  This prints out 16 lines of 16 bytes
  for (int count= 0; count < 16; count++)
  {
    for (int i = 0; i < 16; i++)
    {
      fingerTemplate = String(templateBuffer[count*16+i], HEX);
      fingerTemplate.toUpperCase();
      Serial.print(fingerTemplate);
      }
  }
  Serial.print(">");
  Serial.println();
  
}

I have tried to return the values but I couldn't find a way of getting the whole value, so can help me on how to fix it while using return.

i was thinking that adding return p; at the very end would help.

Serial.print(">");
  Serial.println();
  return p;
}

then there is the issue within loop()

void loop()                     // run over and over again
{
  id = getFingerprintID();
  Serial.println(id);
  while (id == 1 ){
  delay(50);
  id = downloadFingerprintTemplate(id);
//  deleteFingerprint(id);
  break;
  }
  delay(50);            //don't ned to run this at full speed.
//   
}

The whole code is a bit of a mish mesh, if id is a global variable it is not a good idea to create another local variable with the same name. For the variables id & p are not really clear to me what they mean.

Then there is the issue of possible memory fragmentation, though on an ESP rarely a problem, having

String fingerTemplate = "";
String fingerTemplates = "";

these as global variables, and

for (int count= 0; count < 16; count++)
  {
    for (int i = 0; i < 16; i++)
    {
      fingerTemplate = String(templateBuffer[count*16+i], HEX);
      fingerTemplate.toUpperCase();
      Serial.print(fingerTemplate);
      }
  }

only to use it locally (just using the String calss so you can do toUpperCase ? ah well)
The String class uses the heap not the stack though, the stack is used when calling and returning from a function, so there must be something going wrong there. It could be still a bug in the core, are you running the latest version ?

I find that on the ESP32 Adafruit libraries fail to function correctly. Which fingerprint sensor are you using?
The whole String are bad flies out the window with an ESP32.

Hi Deva_Rishi, I saw your reply and changed my variables. I removed all the return p because I was not using in my code and also removed the return datatype. I also changed the fingerTemplate variable from global to local.

#include <Adafruit_Fingerprint.h>

HardwareSerial mySerial(2);
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
uint8_t id = 0;

uint8_t getFingerprintID() {
  uint8_t p = finger.getImage();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image taken");
      break;
    case FINGERPRINT_NOFINGER:
      Serial.println("No finger detected");
      return id;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
    case FINGERPRINT_IMAGEFAIL:
      Serial.println("Imaging error");
    default:
      Serial.println("Unknown error");
  }

  // OK success!

  p = finger.image2Tz();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image converted");
      break;
    case FINGERPRINT_IMAGEMESS:
      Serial.println("Image too messy");
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
    case FINGERPRINT_FEATUREFAIL:
      Serial.println("Could not find fingerprint features");
    case FINGERPRINT_INVALIDIMAGE:
      Serial.println("Could not find fingerprint features");
    default:
      Serial.println("Unknown error");
  }
  id = 1;
 p = finger.storeModel(id);
  if (p == FINGERPRINT_OK) {
    Serial.println("Stored!");
    id = 1;
    return id;
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    Serial.println("Communication error");
  } else if (p == FINGERPRINT_BADLOCATION) {
    Serial.println("Could not store in that location");
  } else if (p == FINGERPRINT_FLASHERR) {
    Serial.println("Error writing to flash");
  } else {
    Serial.println("Unknown error");
  } 
}

void downloadFingerprintTemplate(uint8_t id)
{
  Serial.println("------------------------------------");
  Serial.print("Attempting to load #"); Serial.println(id);
  uint8_t p = finger.loadModel(id);
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" loaded");
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
    default:
      Serial.print("Unknown error "); Serial.println(p);
  }

  // OK success!

   p = finger.getModel();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.println(" transferring:");
      break;
   default:
      Serial.print("Unknown error "); Serial.println(p);
  }


  uint8_t templateBuffer[256];
  memset(templateBuffer, 0xff, 256);  //zero out template buffer
  int index=0;
  uint32_t starttime = millis();
  while ((index < 256) && ((millis() - starttime) < 1000))
  {
    if (mySerial.available())
    {
      templateBuffer[index] = mySerial.read();
      index++;
    }
  }
  
  Serial.print(index); Serial.println(" bytes read");
  Serial.print("<");
  
  //dump entire templateBuffer.  This prints out 16 lines of 16 bytes
  for (int count= 0; count < 16; count++)
  {
    for (int i = 0; i < 16; i++)
    {
      String fingerTemplate = String(templateBuffer[count*16+i], HEX);
      fingerTemplate.toUpperCase();
      Serial.print(fingerTemplate);
      }
  }
  Serial.print(">");
  Serial.println();
  
}

uint8_t deleteFingerprint(uint8_t id) {
  uint8_t p = -1;
  
  p = finger.deleteModel(id);

  if (p == FINGERPRINT_OK) {
    Serial.println("Deleted!");
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    Serial.println("Communication error");
  } else if (p == FINGERPRINT_BADLOCATION) {
    Serial.println("Could not delete in that location");
  } else if (p == FINGERPRINT_FLASHERR) {
    Serial.println("Error writing to flash");
  } else {
    Serial.print("Unknown error: 0x"); Serial.println(p, HEX);
  }   
}

void setup()  
{
  Serial.begin(9600);
  while (!Serial);  // For Yun/Leo/Micro/Zero/...
  delay(100);
  Serial.println("\n\nAdafruit finger detect test");

  // set the data rate for the sensor serial port
  finger.begin(57600);
  
  if (finger.verifyPassword()) {
    Serial.println("Found fingerprint sensor!");
  } else {
    Serial.println("Did not find fingerprint sensor :(");
    while (1) { delay(1); }
  }

  finger.getTemplateCount();
  Serial.print("Sensor contains "); Serial.print(finger.templateCount); Serial.println(" templates");
  Serial.println("Waiting for valid finger...");
}

void loop()                     // run over and over again
{
  id = getFingerprintID();
  Serial.println(id);
  while (id == 1 ){
  delay(50);
  downloadFingerprintTemplate(id);
  break;
  }
  delay(50);            //don't need to run this at full speed.
//   
}

The problem still shows up.

Hi idahowalker, I am using R307 fingerprint sensor.

I found this about the sensor and ESP32 Fingerprint sensor with ESP32 not working [solved] - Microcontrollers - Arduino Forum not sure if it will help.

I feel like this section of code is suspect:

uint8_t templateBuffer[256];
  memset(templateBuffer, 0xff, 256);  //zero out template buffer
  int index=0;
  uint32_t starttime = millis();
  while ((index < 256) && ((millis() - starttime) < 1000))
  {
    if (mySerial.available())
    {
      templateBuffer[index] = mySerial.read();
      index++;
    }
  }
 
  Serial.print(index); Serial.println(" bytes read");
  Serial.print(" <");
 
  //dump entire templateBuffer.  This prints out 16 lines of 16 bytes
  for (int count= 0; count < 16; count++)
  {
    for (int i = 0; i < 16; i++)
    {
      fingerTemplate = String(templateBuffer[count*16+i], HEX);
      fingerTemplate.toUpperCase();
      Serial.print(fingerTemplate);
      }
  }
  Serial.print(">");
  Serial.println();
 
}

The creation of that 256-element byte array occurs on the stack as does the construction of instances of String objects.

Can you move the array to global memory and switch to using standard NULL-terminated strings rather than String objects?

I am not sure of how one does that. Am I to create another function for calling the the array byte and the call the string?

Can U help on how can I call the array byte to global memory.

Just move:

uint8_t templateBuffer[256];

out of the function and put it up top where you declare the fingerprint templates etc.

(I'm probably wrong about where the String objects end up in memory; heap vs stack...)

I don't know why this would be a problem (and it very well may not be) but it's worth a try.

by using a null terminated string, u mean I add the null terminated character at the end of the array.

thanks...I did the changes and by using null terminated string, u mean I add a null terminated character at the end of the array.

By null-terminated string I mean to use something like:

#define MAX_STR_LEN     256
char szNullString[MAX_STR_LEN];

and small-s string functions like sprintf(szNullString, "...) strcat(szNullString, ...) etc to manipulate them.

Capital-S String(...) stuff requires a lot of memory and machine cycles. They are generally frowned upon by the Arduinoista because they're known to cause memory problems and crashes in lesser processors. I don't know if the ESP32 & its compilation/linking tools are susceptible to the same issues but since you're using Strings and are having what appear to be stack issues it makes sense to me to try the alternative.

:slight_smile: Thanks it work. The sprintf was able to print the template. U were write the Serial.print was overloading the core. Thanks alot.

I used the code that had the sprintf to print the template and it worked.

void printHex(int num, int precision) {
    char tmp[16];
    char format[128];
 
    sprintf(format, "%%.%dX", precision);
 
    sprintf(tmp, format, num);
    Serial.print(tmp);
}