ESP32S2 memory corruption (?) crash

sAm_vdP
Posts: 1
Joined: Sun Jun 29, 2025 11:46 am

ESP32S2 memory corruption (?) crash

Postby sAm_vdP » Sun Jun 29, 2025 12:13 pm

Hi,

I am facing an issue with a project on an ESP32S2 (Wemos S2 Mini) and I'm about to go insane.

In a nutshell, my startup code has started crashing once I added some print statements in a completely other class. I therefore believe I have some sort of memory corruption issue, but I can't seem to track it down. The behavior is utterly baffling to me.

This is the crashing function:

Code: Select all

template <class T>
void Display::debugPrint(T message)
{
    Serial.print("this: ");
    Serial.println((int)this);
    Serial.print("&current_debug_display_: ");
    Serial.println((int)&current_debug_display_);
    Serial.print("current_debug_display_: ");
    Serial.println((int)current_debug_display_);
    Serial.println("\n");
    delay(500);

    current_debug_display_->print(message);
}
current_debug_display_ is pointer to an Adafruit_SSD1322 display. This pointer is correctly initialized.

Inside the setup() function, I call this code like this:

Code: Select all

	Serial.print("&display: ");
	Serial.println((int)&display);
	Serial.print("display.current_debug_display_: ");
	Serial.println((int)display.current_debug_display_);
	Serial.print("&display.current_debug_display_: ");
	Serial.println((int)&display.current_debug_display_);
	Serial.println("---");
	display.debugPrint("Loading...\n");
The output on the serial terminal is this:

Code: Select all

&display:                        1073497384
&display.current_debug_display_: 1073497576
display.current_debug_display_:  1073497400
---
this:                            1073497384
&current_debug_display_:         1073497559
current_debug_display_:          -256
Note the weirdness: The address of the current_debug_display_ member variable is wrong. As a result, the pointer is also wrong. What's curious is that the display object is not actually corrupted. If I read current_debug_display_ based on the 'this' pointer and the 192 byte offset, I get the correct value.

Then the program crashes, with this backtrace:

Code: Select all

================== CURRENT THREAD REGISTERS ===================
exccause       0x1c (LoadProhibitedCause)
excvaddr       0xffffff00

...
======================== THREADS INFO =========================
#0  0x40085ae5 in Print::write (this=0xffffff00, str=0x3f000b05 "Loading...
") at C:/Users/samvdp/.platformio/packages/framework-arduinoespressif32/cores/esp32/Print.h:67
#1  0x40086248 in Print::print (this=0xffffff00, str=0x3f000b05 "Loading...
") at C:/Users/samvdp/.platformio/packages/framework-arduinoespressif32/cores/esp32/Print.cpp:90
#2  0x40082900 in Display::debugPrint<char const*> (this=0x3ffc4528 <display>, message=0x3f000b05 "Loading...
") at include/Display.h:111
#3  0x40083540 in setup () at src/main.cpp:68
#4  0x40088855 in loopTask (pvParameters=0x0) at C:/Users/samvdp/.platformio/packages/framework-arduinoespressif32/cores/esp32/main.cpp:42
The crash isn't really that surprising at this point.

Another thing I don't understand: The main loop of this project is just

Code: Select all

void loop()
{
	display.debugPrint("Yeah?\n");
	delay(250);
}
But this is never actually executed, because of the crash in setup(). However, if I leave the loop empty, like so:

Code: Select all

void loop()
{}
Then everything works and I get the expected serial output:

Code: Select all

&display:                        1073497384
&display.current_debug_display_: 1073497576
display.current_debug_display_:  1073497400
---
this:                            1073497384
&current_debug_display_:         1073497576
current_debug_display_:          1073497400
Any idea what might be going on here? I have been banging my head against this problem for hours and I am becoming desperate.

I would highly appreciate any suggestions on what to try!

Thanks,
Bart


EDIT:
I added one more check. I'm doing a

Code: Select all

Serial.println(sizeof(Display));
at the beginning of the crashing function. I should return 204, but actually returns 187 before the crash.

If I look at the coredump in gdb, the code seems to be correct

Code: Select all

  0x40083af0 <_ZN7Display11debugPrint2IPKcEEvT_>          entry   a1, 32                                             
  0x40083af3 <_ZN7Display11debugPrint2IPKcEEvT_+3>        l32r    a7, 0x4008009c <_stext+124> (0x3ffc4a88 <USBSerial>
  0x40083af6 <_ZN7Display11debugPrint2IPKcEEvT_+6>        movi.n  a12, 10                                            
  0x40083af8 <_ZN7Display11debugPrint2IPKcEEvT_+8>        movi    a11, 204                                          
  0x40083afb <_ZN7Display11debugPrint2IPKcEEvT_+11>       mov.n   a10, a7                                           
  0x40083afd <_ZN7Display11debugPrint2IPKcEEvT_+13>       call8   0x4008721c <_ZN5Print7printlnEji>          
As far as I understand, movi a11, 204 loads the correct value into the register and then it prints something completely different. How is that even possible?

RandomInternetGuy
Posts: 82
Joined: Fri Aug 11, 2023 4:56 am

Re: ESP32S2 memory corruption (?) crash

Postby RandomInternetGuy » Thu Jul 31, 2025 5:38 pm

Symptoms like this in ESP32-land are usually stack overflows. The default task stack is somewhat small. Declaring and using a large stack object somewhere can cause crashes that show up in "unrelated" (these are computers; nothing is random - it's just not obvious) places.

There are some configuration options somewhere to instrument stack usage to help you find it and bring you right into the debugger, but knowing your code is always the best way to recognize it.

Of course, the shotgun approach is to just make your task stacks larger and see if that puts it into remission or at least moves it around. That'll tell you if you're on the right track.

lbernstone
Posts: 1132
Joined: Mon Jul 22, 2019 3:20 pm

Re: ESP32S2 memory corruption (?) crash

Postby lbernstone » Thu Jul 31, 2025 6:16 pm

printRunningTasks(Serial) is a handy little function to show stack usage
The ArduinoStackSize example shows how to set the loop task size. The default is 8K.

Who is online

Users browsing this forum: Bing [Bot] and 1 guest