Assert failed and other fatal errors when handling the HTTP server

Actually, I'm not sure if this is a firmware of hardware issue.
I have two units of my board (custom board with ESP32). Unfortunately I don't have both with me: one is miles away so I cannot run both in the same conditions.

My board works fine, the other crashes very often in a specific circumstance.
The errors he gets are quite different, here some of them:

CORRUPT HEAP: Bad head at 0x3fff7f40. Expected 0xabba1234 got 0x3ffe4364

assert failed: multi_heap_free multi_heap_poisoning.c:259 (head != NULL)

assert failed: xQueueGenericSend queue.c:821 (!( ( pvItemToQueue == ((void *)0) ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ))

assert failed: spinlock_acquire spinlock.h:122 (result == core_id || result == SPINLOCK_FREE)

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

Despite they are different, the "good" news is they happen in two specific case: when I turn on or off the HTTP server.

I'm not able to produce a minimal code that exibhits the issue and the whole firmware it way too big to be published here (and I can't anyway). What I've observed is:

  1. my board almost work in any case
  2. his board crashes almost every time it trigger the on/off of the webserver
  3. how often this happens changes when I change other part of the firmware (the code below is unchanged from several months)

Point 3. led me to think about a memory corruption issue, but if it was the case I should see the same behavior on my board, shouldn't I?

Here the relevant code, hoping I'm doing something wrong here:

void Network::goProvisioning()
{
    if (webapp.IsRunning()) webapp.End();
    if (sntp_enabled) sntp_stop();
    WiFi.mode(WIFI_OFF);
    while (static_cast<int8_t>(WiFi.status()) > WL_IDLE_STATUS)
    {
        yield();
        delay(500);
    }
    _provisioning.Begin(Ssid().c_str(), PASSWORD);
}

void WebApp::Begin()
{
  MDNS.begin(APP_NAME);
  MDNS.addService("http", "tcp", 80);
  _server.serveStatic("/", LittleFS, "/www")
      .setDefaultFile("index.html")
      .setTemplateProcessor(std::bind(&WebApp::processor, this, std::placeholders::_1));

  _server.onNotFound([](AsyncWebServerRequest *request)
  { 
      request->send(404); 
  });

  _server.begin();
  _isRunning = true;
  Serial.println(F("[WEB] HTTP server started"));
}

void WebApp::End()
{
  _server.end();
  Serial.println(F("[WEB] HTTP server stopped"));
  _isRunning = false;
}

void ESP32WiFiProvisioning::End()
{
  _requestEnd = false;
  _server.end();
  MDNS.end();
  _state = ProvisioningStates::Idle;
}

void ESP32WiFiProvisioning::Begin(const char *ssid, const char *password)
{
  if (onProvisionCallback) onProvisionCallback();
  strncpy(_ssid, ssid, sizeof(_ssid));
  strncpy(_password, password, sizeof(_password));

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  startScan();
}

void ESP32WiFiProvisioning::startAP()
{
  WiFi.mode(WIFI_AP);
  while (WiFi.getMode() != WIFI_AP)
  {
    delay(500);
    yield();
  }
  
  WiFi.softAPConfig(apIP, apIP, netMsk);
  WiFi.softAP(_ssid, _password);
  WiFi.softAPsetHostname(APP_NAME);

  Serial.printf("[WP] Start DNS: %s\n",_dns.start(53, "*", WiFi.softAPIP()) ? "success" : "failed");
  Serial.println("[WP] AP IP address: " + WiFi.softAPIP().toString());
  Serial.print("[WP] AP SSID: ");
  Serial.println(_ssid);
  Serial.print("[WP] AP password: ");
  Serial.println(_password);

  _server.on("/api/close", HTTP_POST, [this](AsyncWebServerRequest *request)
  {
    _requestEnd = true;
    request->redirect(F("/exit-provisioning.html"));
  });

  _server.serveStatic("/", LittleFS, "/www")
      .setDefaultFile("wifi.html")
      .setTemplateProcessor(std::bind(&ESP32WiFiProvisioning::processor, this, std::placeholders::_1));

  _server.on("/", HTTP_POST, [this](AsyncWebServerRequest *request)
  { 
    this->handleConfigureRequest(request);
    request->redirect(F("/exit-provisioning.html"));
  });

  _server.onNotFound([](AsyncWebServerRequest *request)
  { 
    request->send(404); 
  });

  _server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);

  _server.begin();
  _state = ProvisioningStates::Run;
  Serial.println("[WP] HTTP server started");
}

void ESP32WiFiProvisioning::Stop()
{
  _dns.stop();  
  WiFi.mode(WIFI_OFF);  
}

int ESP32WiFiProvisioning::convertRRSItoLevel(int rssi)
{
  //  Convert RSSI to 0 - 4 Step level
  int numlevels = 4;
  int MIN_RSSI = -100;
  int MAX_RSSI = -55;

  if (rssi < MIN_RSSI) return 0;
  else if (rssi >= MAX_RSSI) return numlevels;
  else
  {
    int inputRange = MAX_RSSI - MIN_RSSI;
    int res = std::ceil((rssi - MIN_RSSI) * numlevels / inputRange);
    if (res == 0) return 1;
    return res;
  }
}

void ESP32WiFiProvisioning::startScan()
{
#ifdef DEBUG
  Serial.println("[WP] Starting Network Scan...");
#endif

  WiFi.scanNetworks(true);
  _scanCount = WIFI_SCAN_RUNNING;
  _state = ProvisioningStates::Scan;
}

void ESP32WiFiProvisioning::loopScan() 
{
    _scanCount = WiFi.scanComplete();
    switch (_scanCount)
    {
    case WIFI_SCAN_RUNNING:
    case WIFI_SCAN_FAILED:
      delay(50);
      break;

    case 0:
      Serial.println("[WP] No networks found");
      break;
    
    default:
      Serial.printf("[WP] Found %d networks\n", _scanCount);
    }
}

void ESP32WiFiProvisioning::Fsm()
{
  _dns.processNextRequest();

  switch (_state)
  {
  case ProvisioningStates::Scan:
  {
    if (_scanCount < 0) loopScan();
    else
    {
      storeAvailableNetworks(_scanCount);
      startAP();
    }
  }
  break;

  default:
    break;
  }
}

Most of the time when I get the crash with one of the errors above the last printed debug string is:

[WEB] HTTP server stopped"

Of course I cannot be 100% sure if is something else that happens before a new debug string is printed.

I asked him to change its power supply, but the errors are still there.
I'm not able to reproduce the issue here and it's hard to do lot of trials with different debug printf given the distances.

I'm aware you don't have the cristall ball :laughing: but I'm just looking for some advice to put me on the right path:

  • it could be a firmware issue even if it triggers on one board only?
  • may it depend by the specific routers/wifi networks?
  • can an hardware issue triggers differently when changing other part of code?
  • can I enable in some way a verbose debug of ESP32? Perhaps it tells me more information

Of course if I cannot solve in this way I have to ask him to give me back its item and test on my desk with the working item aside.

I've just discovered I can add:

monitor_filters = esp32_exception_decoder

in platformio.ini. I'm going to ask him to report the decoded backtrace!

It appears you have pointer issues in your queueing code. All I can advise is keep it simple, keep it modular and probably rewrite it.

What is the "queuing code"?

I see Queue 4 times, that statement appears to be checking for valid data to send. Also spinlocks are commonly used in multi-process or threaded apps that use shared memory (queues) to ensure atomic operations.

I don't use "queues" in my code, or at least I'm not aware of.
I apologize for my incompetence, but what I should looking for in my code to be sure I don't use queues?

You may not be using them directly, but one of your libraries is.
In any case, your first error msg tells you that you have memory issues. The rest of the errors are related but nothing in them tells us what to fix. I am afraid you will need to either single step or trap the error. I used to do that when I was working as a professional programmer some 20 years ago but have no clue as to how to do it now.
It should be part of your training, but if you are just a hobbyist, you may not know how.
Maybe someone else will be able to give you better advice, sorry I can't help at this point.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.