espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.32k stars 7.36k forks source link

Class variables of type (T)emplate memory corruption #2364

Closed Crypter closed 5 years ago

Crypter commented 5 years ago

Hardware:

Board: ESP32 Dev Module & Node32S Release: 1.0.1 & 1.0.0 - using Arduino Boards Manager IDE name: Arduino IDE Flash Frequency: 80Mhz, I think PSRAM enabled: no Upload Speed: Any Computer OS: Windows 7 64bit

Description:

I'm trying to use LinkedList.h type of structure in my project. Linked lists by nature accept all kinds of data structures, hence using templates as their data type (from now on 'T'). Any interaction, outside of the loop task, with pointers of data type T makes ESP32 crash. I stripped everything I could so that I can give you the simplest example that crashes consistently.

I honestly hope I'm doing something wrong and this is not a compiler bug.

Sketch:

#include <Ticker.h>

template<typename T> class templateClass {
  public:
    virtual void set(T item);
    T *storage = 0;
};

template<typename T> void templateClass<T>::set(T item) {
  storage = new T(item);
}

class testClass {
  public:
    Ticker tick;
    templateClass<int> testList;

    void call_from_ticker_or_separate_RTOS_task() {
      Serial.println("I FAIL!");
      testList.set(1);
    }

    void call_from_loop_or_web_server_callback_handler() {
      Serial.println("I WORK!");
      testList.set(1);
    }

    void begin() {
      tick.attach(3.0, reinterpret_cast<Ticker::callback_t>(&testClass::call_from_ticker_or_separate_RTOS_task));
    }
};

testClass testClassInstance;

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.println("ESP32 ALIVE!");
  testClassInstance.begin();
}

void loop() {
  delay(1000);
  testClassInstance.call_from_loop_or_web_server_callback_handler();
}

Serial Output:

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:9280
load:0x40080400,len:5848
entry 0x40080698
ESP32 ALIVE!
I WORK!
I WORK!
I WORK!
I FAIL!
Guru Meditation Error: Core  0 panic'ed (StoreProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x400d0b2a  PS      : 0x00060b30  A0      : 0x800d0b45  A1      : 0x3ffb78b0  
A2      : 0x00000004  A3      : 0x00000001  A4      : 0x00000050  A5      : 0x00000001  
A6      : 0x00000000  A7      : 0x00000000  A8      : 0x800d0b28  A9      : 0x3ffb7890  
A10     : 0x3ffb8494  A11     : 0x00000001  A12     : 0x00060520  A13     : 0x00000001  
A14     : 0x00060523  A15     : 0x00000000  SAR     : 0x00000000  EXCCAUSE: 0x0000001d  
EXCVADDR: 0x00000008  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff  

Backtrace: 0x400d0b2a:0x3ffb78b0 0x400d0b42:0x3ffb78d0 0x400d4c28:0x3ffb78f0 0x400d4c8f:0x3ffb7910 0x40089639:0x3ffb7930

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

Debug Messages:


PC: 0x400d0986: templateClass ::set(int) at C:\Users\Crypter\Documents\Arduino\test/test.ino line 16
EXCVADDR: 0x00000008

Decoding stack results
0x400d0986: templateClass ::set(int) at C:\Users\Crypter\Documents\Arduino\test/test.ino line 16
0x400d09c5: testClass::testMemberFunction() at C:\Users\Crypter\Documents\Arduino\test/test.ino line 25
0x400d45cc: timer_process_alarm at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/esp_timer.c line 284
0x400d462b: timer_task at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/esp_timer.c line 311
OttoWinter commented 5 years ago

You're using reinterpret_cast which is potentially unsafe.

Why is call_from_ticker_or_separate_RTOS_task() not static? I think the problem might be that the method is supposed to be run with a this pointer as first argument - by reinterpreting the class method pointer you're removing that.

Crypter commented 5 years ago

Why is call_from_ticker_or_separate_RTOS_task() not static? I think the problem might be that the method is supposed to be run with a this pointer as first argument - by reinterpreting the class method pointer you're removing that.

I think you might be right, I didn't see this before. I'll give it a try once I get back home and report my success.

Crypter commented 5 years ago

@OttoWinter thank you for your help! This was the solution to my problem:

static void testClass::member_function_callback_wrapper( void * context ){ 
    ((testClass*)context)->member_function();
}

void testClass::begin() {
    ticker.attach(3.0, &testClass::member_function_callback_wrapper, (void*)(this));
}

Issue closed, and I'm glad it was me doing something wrong :)