ESP8266 crashes at random times: Exception 3; Running out of Heap Memory?

Hi guys,

i built a lamp which can be controlled over a webserver (using ESPAsyncWebserver).
The client is communicating with the server through a websocket.
My code uploads without any errors and works fine for some time.
However, when pushing some buttons etc. on the webpage, the program crashes, throwing me Exception 3 (LoadStoreErrorCause) and the stack trace. It crashes at random times, between 6s and 1min, and only when in active usage (interacting with the website).

Why is this happening and how can I fix this?
I found out online that it may have something to do with the chip running out of heap memory...
Is it because of the Strings instead of char arrays?

EDIT 1: I found out during testing, that it has nothing to do with the FastLED library (simplified my code in the question accordingly) and the crash almost never happens if i wait 2s between every input. As soon as I start clicking faster, it crashes again.

Below is my code (I'm sorry it is rather long, I wasn't able to recreate the problem with less code) and the decoded exception code.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include "webpage_hexalamp.h";
#include <Arduino_JSON.h>

const char* ssid = "M MAIN";
const char* password = "21832040298146194648";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create a WebSocket object
AsyncWebSocket ws("/ws");

JSONVar values;

int colorValues[3];
int brightness = 50;
double speed = 1;
String activeLightmode = "none";
bool powerOn = false;


void brightnessUpdate() {
  // Do something
}

void powerButton(){
  // Do something
}


// Websocket Handling ---------------------------------------------------------------------------------------------------------------------------------------------------------------------

String getValues(){
  values["brightness"] = String(brightness);
  values["speed"] = String(speed);
  values["activeLightmode"] = String(activeLightmode);
  values["powerOn"] = powerOn ? "true" : "false";

  String jsonString = JSON.stringify(values);
  return jsonString;
}

//Send all active clients current values
void notifyClients(String values) {
  ws.textAll(values);
}

//Websocket Communication: New message from client
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    String message = "";
    data[len] = 0;
    message = (char*)data;
    // Brightness and Speed Slider
    if (message.indexOf("slider") >= 0) {
      if(message.startsWith("brightness")){
        brightness = message.substring(22).toInt();
        brightnessUpdate();
      } else{
        speed = message.substring(17).toDouble();
      }
      if(message.indexOf("Send") >= 0) {
        notifyClients(getValues());
      }
    }
    // Lightmodes
    else if (message.indexOf("lightmodeI") >= 0) {
      activeLightmode = message.substring(10);
      notifyClients(getValues());
    }
    // Power Button    
    else if (message.indexOf("powerI") >= 0) {
      if(message.substring(6) == "On"){
        powerOn = true;
      } else {
        powerOn = false;
      }
      powerButton();
      notifyClients(getValues());

    //RGB Color Picker
    } else if (message.indexOf("TTT") >= 0) {
      char* charMessage = const_cast<char*>(message.c_str());
      colorValues[0] = atoi(strtok(charMessage, "T"));
      colorValues[1] = atoi(strtok(NULL, "T"));
      colorValues[2] = atoi(strtok(NULL, "T"));
    }
     else{
      Serial.println(message);
    }
    if (strcmp((char*)data, "getValues") == 0) {
      notifyClients(getValues());
    }
  }
}

// Eventhandler for Websocket Events
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
      handleWebSocketMessage(arg, data, len);
      break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
      break;
  }
}

void setup() {
  Serial.begin(115200);
  initWiFi();

  initWebSocket();
  // Web Server Root URL
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/html", webpage_hexalamp);
  });
  server.begin();

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void loop() {
  ws.cleanupClients();
}

Decoded Error Message in Serial Monitor:

Exception 3: LoadStoreError: Processor internal physical address or data error during load or store

PC: 0x401067f3: is in umm_disconnect_from_free_list(umm_heap_context_t*, uint16_t) (C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\umm_malloc\umm_malloc.cpp:395).

EXCVADDR: 0x4004439e

Decoding stack results

0x401007fa: is in umm_free_core(umm_heap_context_t*, void*) (C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\umm_malloc\umm_malloc.cpp:642).

0x402040b6: AsyncWebSocketClient::_queueMessage(AsyncWebSocketMessage*) at c:\Users\leosp\Documents\Arduino\libraries\ESPAsyncWebServer\src\StringArray.h:32

0x40100b48: free(void*) at C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\umm_malloc\umm_malloc.cpp:688

0x4020330c: is in std::_Function_handler<void(AsyncWebSocketMessageBuffer* const&), AsyncWebSocket::AsyncWebSocket(const String&)::<lambda(AsyncWebSocketMessageBuffer*)> >::_M_invoke(const std::_Any_data &, AsyncWebSocketMessageBuffer * const&) (c:\Users\leosp\Documents\Arduino\libraries\ESPAsyncWebServer\src\AsyncWebSocket.cpp:853).

0x40203481: AsyncWebSocket::_cleanBuffers() at c:\Users\leosp\Documents\Arduino\libraries\ESPAsyncWebServer\src\StringArray.h:33

0x40202675: is in handleWebSocketMessage(void*, unsigned char*, unsigned int) (C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266/WString.h:115).

0x4020dd94: is in AsyncWebSocket::_handleEvent(AsyncWebSocketClient*, AwsEventType, void*, unsigned char*, unsigned int) (c:\users\leosp\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\3.1.0-gcc10.3-e5f9fec\xtensa-lx106-elf\include\c++\10.3.0\bits/std_function.h:617).

0x40100b48: free(void*) at C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\umm_malloc\umm_malloc.cpp:688

0x40203ef8: is in AsyncWebSocketClient::_onData(void*, unsigned int) (c:\Users\leosp\Documents\Arduino\libraries\ESPAsyncWebServer\src\AsyncWebSocket.cpp:691).

0x40208888: is in AsyncClient::_recv(std::shared_ptr<ACErrorTracker>&, tcp_pcb*, pbuf*, int) (c:\Users\leosp\Documents\Arduino\libraries\ESPAsyncTCP\src/ESPAsyncTCP.h:103).

0x402088e8: is in AsyncClient::_s_recv(void*, tcp_pcb*, pbuf*, int) (c:\users\leosp\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\3.1.0-gcc10.3-e5f9fec\xtensa-lx106-elf\include\c++\10.3.0\bits/shared_ptr_base.h:1324).

0x4020b020: loop_wrapper() at C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:252

0x4021af69: tcp_input at core\tcp_in.c:501

0x4021fec9: ip4_input at core/ipv4\ip4.c:1467

0x40217bc1: mem_malloc at core\mem.c:210

0x401007fa: is in umm_free_core(umm_heap_context_t*, void*) (C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\umm_malloc\umm_malloc.cpp:642).

0x40217285: ethernet_input_LWIP2 at netif\ethernet.c:188

0x40217098: esp2glue_ethernet_input at glue-lwip\lwip-git.c:118

0x4023fb5d: ethernet_input at glue-esp\lwip-esp.c:365

0x4023fb6f: ethernet_input at glue-esp\lwip-esp.c:373

0x401000ab: app_entry_redefinable() at C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:386

0x40100274: is in ets_post(uint8, ETSSignal, ETSParam) (C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:238).

0x40100274: is in ets_post(uint8, ETSSignal, ETSParam) (C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:238).

0x40100274: is in ets_post(uint8, ETSSignal, ETSParam) (C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:238).

0x4020ca44: run_scheduled_recurrent_functions() at C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_features.h:64

0x40100274: is in ets_post(uint8, ETSSignal, ETSParam) (C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:238).

0x40100274: is in ets_post(uint8, ETSSignal, ETSParam) (C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:238).

0x40100274: is in ets_post(uint8, ETSSignal, ETSParam) (C:\Users\leosp\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.1.2\cores\esp8266\core_esp8266_main.cpp:238).

0x40204398: is in AsyncWebSocket::count() const (c:\Users\leosp\Documents\Arduino\libraries\ESPAsyncWebServer\src/StringArray.h:35).

0x402043d8: is in AsyncWebSocket::cleanupClients(unsigned short) (c:\Users\leosp\Documents\Arduino\libraries\ESPAsyncWebServer\src\AsyncWebSocket.cpp:922).

0x402043c4: is in AsyncWebSocket::cleanupClients(unsigned short) (c:\Users\leosp\Documents\Arduino\libraries\ESPAsyncWebServer\src\AsyncWebSocket.cpp:922).

0x40202314: is in CPixelLEDController<(EOrder)66, 1, 4294967295u>::show(CRGB const*, int, CRGB) (c:\Users\leosp\Documents\Arduino\libraries\FastLED\src/controller.h:289).

0x4021899a: tcp_listen_with_backlog_and_err at core\tcp.c:916

0x40208ff4: is in CFastLED::show(unsigned char) (c:\Users\leosp\Documents\Arduino\libraries\FastLED\src/controller.h:183).

0x402090a5: is in CFastLED::addLeds(CLEDController*, CRGB*, int, int) (c:\Users\leosp\Documents\Arduino\libraries\FastLED\src\FastLED.cpp:51).

0x4020439e: is in AsyncWebSocket::count() const (c:\Users\leosp\Documents\Arduino\libraries\ESPAsyncWebServer\src/StringArray.h:35).

0x4020dd48: is in std::_Function_handler<bool(AsyncWebSocketClient* const&), AsyncWebSocket::count() const::<lambda(AsyncWebSocketClient*)> >::_M_manager(std::_Any_data &, const std::_Any_data &, std::_Manager_operation) (c:\users\leosp\appdata\local\arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\3.1.0-gcc10.3-e5f9fec\xtensa-lx106-elf\include\c++\10.3.0\bits/std_function.h:268).

Would be great if anyone is able to help, I already spent hours working on this problem.
If I should modify my question and provide more data, please just tell me!
Thanks in advance!

Maybe

#define FASTLED_INTERRUPT_RETRY_COUNT 0

From here
https://community.smartthings.com/t/addressable-leds/104207/30?page=2

Unfortunately didn't work, but thank you! I found out during more testing, that it has nothing to do with the FastLED library

hi,
The setup does not seem to have a close bracket at the end, although I don't think it would compile like that.

I probably deleted it unintentionally when copying the code to the question. In the original code there is one of course.

This is most likely a heap buffer overflow.

So for anyone in the future with a similar problem:
Apparently the websocket sending data to all clients ("ws.textAll()") causes memory corruption.
I just removed that feature from my project since it's not that important, now it's working perfectly.
There is also a labour intensive work-around if you need the feature: Crash in AsyncWebSocket::textAll(String const&) · Issue #900 · me-no-dev/ESPAsyncWebServer · GitHub