Page 1 of 1

stack/heap memory corruption?

Posted: Mon Apr 29, 2024 3:37 am
by hyuan75
ESP32 IDF release:v5.2.1
Development board/Harware:ESP32-LyraTD-MSC , ESP32 v1.0

This is a very simple https communication application, just copied and modified from IDF sample application of "esp_http_client".
app_main code copied below, the FreeRTOS task is created with stack size of 8192(8K), should be enough?

Code: Select all

void app_main(void)
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    if(ESP_OK!=connect_wifi()){
        ESP_LOGE(TALKTAG,"Connect to Wifi is fail, aborting...");
    } else{
       ESP_LOGI(TALKTAG, "Connected to Wifi, starting the application...");
       xTaskCreate(&app_task, "app_task", 8192, NULL, 5, NULL);
    }
}
Task's entry function as below:

Code: Select all

static void app_task(void *pvparameters)
{
    talk_to_server();
    ESP_LOGI(TALKTAG, "Finish talking to server.");
    for (int countdown = 10; countdown >= 0; countdown--) {
        ESP_LOGI(TALKTAG, "%d...", countdown);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }    
    vTaskDelete(NULL);
}
task entry functions calls talk_to server, the code is below:

Code: Select all

void talk_to_server(void)
{
    char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER+1] = {0};
    esp_http_client_config_t config = {
        .url = SERVER_WEB_URL,
        .event_handler = _http_event_handler,
        .crt_bundle_attach = esp_crt_bundle_attach,
        .user_data = local_response_buffer,
        //.method = HTTP_METHOD_POST,
    };

    esp_http_client_handle_t client = esp_http_client_init(&config);

    ...
	//
	
	...

    esp_http_client_cleanup(client);

}
if the MACRO(MAX_HTTP_OUTPUT_BUFFER) to be defined as 1024, then Stack overflow will happen:

#define MAX_HTTP_OUTPUT_BUFFER 1024

***ERROR*** A stack overflow in task talk_to_server_task has been detected.


Backtrace: 0x40081796:0x3ffcdf00 0x40089091:0x3ffcdf20 0x40089f8a:0x3ffcdf40 0x4008b273:0x3ffcdfc0 0x4008a094:0x3ffcdfe0 0x4008a046:0x00000000 |<-CORRUPTED
0x40081796: panic_abort at C:/Users/hyuan/esp/esp-idf/components/esp_system/panic.c:472
0x40089091: esp_system_abort at C:/Users/hyuan/esp/esp-idf/components/esp_system/port/esp_system_chip.c:93
0x40089f8a: vApplicationStackOverflowHook at C:/Users/hyuan/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:553
0x4008b273: vTaskSwitchContext at C:/Users/hyuan/esp/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:3630 (discriminator 7)
0x4008a094: _frxt_dispatch at C:/Users/hyuan/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S:451
0x4008a046: _frxt_int_exit at C:/Users/hyuan/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/portasm.S:246

If reduce MAX_HTTP_OUTPUT_BUFFER to 512,then applcation runs smoothly and can get server's response.
#define MAX_HTTP_OUTPUT_BUFFER 512

If increasing MAX_HTTP_OUTPUT_BUFFER to 2048,then HEAP will be corrupted,crash.

============================================================================
Compiled result(DRAM/IRAM usage) as below when #define MAX_HTTP_OUTPUT_BUFFER 512 :

Total sizes:
Used static DRAM: 33852 bytes ( 146884 remain, 18.7% used)
.data size: 15348 bytes
.bss size: 18504 bytes
Used static IRAM: 91606 bytes ( 39466 remain, 69.9% used)
.text size: 90579 bytes
.vectors size: 1027 bytes
Used Flash size : 847223 bytes
.text: 623595 bytes
.rodata: 223372 bytes
Total image size: 954177 bytes (.bin may be padded larger)

I (492) cpu_start: ESP-IDF: v5.2.1
I (497) cpu_start: Min chip rev: v0.0
I (502) cpu_start: Max chip rev: v3.99
I (507) cpu_start: Chip rev: v1.0
I (512) heap_init: Initializing. RAM available for dynamic allocation:
I (519) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (525) heap_init: At 3FFB8440 len 00027BC0 (158 KiB): DRAM
I (531) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (537) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (544) heap_init: At 400965D8 len 00009A28 (38 KiB): IRAM
I (552) spi_flash: detected chip: generic
I (555) spi_flash: flash io: dio
I (560) main_task: Started on CPU0
I (570) main_task: Calling app_main()



Compiled result(DRAM/IRAM usage) as below when #define MAX_HTTP_OUTPUT_BUFFER 1024 :
Total sizes:
Used static DRAM: 33852 bytes ( 146884 remain, 18.7% used)
.data size: 15348 bytes
.bss size: 18504 bytes
Used static IRAM: 91606 bytes ( 39466 remain, 69.9% used)
.text size: 90579 bytes
.vectors size: 1027 bytes
Used Flash size : 847179 bytes
.text: 623551 bytes
.rodata: 223372 bytes
Total image size: 954133 bytes (.bin may be padded larger)

I (492) cpu_start: ESP-IDF: v5.2.1
I (497) cpu_start: Min chip rev: v0.0
I (502) cpu_start: Max chip rev: v3.99
I (507) cpu_start: Chip rev: v1.0
I (512) heap_init: Initializing. RAM available for dynamic allocation:
I (519) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (525) heap_init: At 3FFB8440 len 00027BC0 (158 KiB): DRAM
I (531) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (537) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (544) heap_init: At 400965D8 len 00009A28 (38 KiB): IRAM
I (551) spi_flash: detected chip: generic
I (554) spi_flash: flash io: dio
I (559) main_task: Started on CPU0
I (569) main_task: Calling app_main()


============================================================================
I think it should be the size of local variable(local_response_buffer) defined in talk_to_server has impact to memory(DRAM), either stack overflow, or heap corruption:

void talk_to_server(void)
{
char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER+1] = {0};
.....
}

The further experiment(using heap) seems tell it has relationship with memory allocation, please refer to below code change in talk_to_server:

Changing local var of local_response_buffer in talk_to_server function to allocate memory from heap, and print free heap size before/after allocation:

Code: Select all


#define MAX_HTTP_OUTPUT_BUFFER 512*4

void talk_to_server(void)
{
    char *local_response_buffer = NULL;
    int heapleft = heap_caps_get_free_size(MALLOC_CAP_8BIT);
    ESP_LOGI(TALKTAG, "free heap before malloc :\n%d ", heapleft);
    local_response_buffer = malloc(MAX_HTTP_OUTPUT_BUFFER+ 1);
    heapleft = heap_caps_get_free_size(MALLOC_CAP_8BIT);
    ESP_LOGI(TALKTAG, "free heap after malloc :\n%d ", heapleft);
    if (NULL != local_response_buffer)
    {
   	 esp_http_client_config_t config = {
       		 .url = SERVER_WEB_URL,
       		 .event_handler = _http_event_handler,
     		 .crt_bundle_attach = esp_crt_bundle_attach,
    		 .user_data = local_response_buffer,
	        //.method = HTTP_METHOD_POST,
  		  };

  	  esp_http_client_handle_t client = esp_http_client_init(&config);

    	  ...
	 //
	
	  ...

    	 esp_http_client_cleanup(client);
    }

}
from log information of free heap size before/after malloc, heap should be sufficient( there're more than 100K free heap either before or after allocation):

I (1879) Talk: free heap before malloc :
195024
I (1889) Talk: free heap after malloc :
192968

I (1919) main_task: Returned froGuru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.

Core 0 register dump:
PC : 0x40108c46 PS : 0x00060130 A0 : 0x8010a7e8 A1 : 0x3ffc02e0
0x40108c46: ieee80211_send_setup at ??:?

A2 : 0x00000001 A3 : 0x3ffd1208 A4 : 0x3ffb7fbc A5 : 0x00000010
A6 : 0x00000005 A7 : 0x00000005 A8 : 0x3ffb7fbc A9 : 0x3ffc02d0
A10 : 0x00000048 A11 : 0x00000003 A12 : 0x00000018 A13 : 0x00000000
A14 : 0x00000001 A15 : 0x00000000 SAR : 0x00000011 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000001 LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0x00000000
0x4000c46c: memset in ROM
0x4000c477: memset in ROM



Backtrace: 0x40108c43:0x3ffc02e0 0x4010a7e5:0x3ffc0310 0x4010a828:0x3ffc0350 0x40116c16:0x3ffc0370 0x4011719f:0x3ffc0390 0x40117c6f:0x3ffc03b0 0x401191d5:0x3ffc03d0 0x40164599:0x3ffc03f0 0x40092216:0x3ffc0410 0x40089b9d:0x3ffc0440
0x40108c43: ieee80211_send_setup at ??:?
0x4010a7e5: ieee80211_encap_null_data at ??:?
0x4010a828: ieee80211_pm_tx_null_process at ??:?
0x40116c16: pm_send_nullfunc at ??:?
0x4011719f: pm_go_to_sleep at ??:?
0x40117c6f: pm_active_timeout_process at ??:?
0x401191d5: dbg_lmac_ps_statis_reset at ??:?
0x40164599: pp_timer_do_process at ??:?
0x40092216: ppTask at ??:?
0x40089b9d: vPortTaskWrapper at C:/Users/hyuan/esp/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:134





ELF file SHA256: 4a040b880

CPU halted.

There must be memory/DRAM/heap overlapping, who can give a hint where is the problem???

Re: stack/heap memory corruption?

Posted: Mon Apr 29, 2024 6:31 am
by ESP_Sprite
local_response_buffer in talk_to_server is a stack variable, that is, the RAM for it is allocated on the stack. If the free space on the stack is too small to contain this buffer, you'll get weird behaviour: if it overflows the stack by just a bit, ESP-IDF can detect this and you'll get an error indicating that; if it's a big overflow you may overwrite something else before ESP-IDF can detect the issue.

Anyway, at the moment you're allocating 8192 bytes for the task stack where that function runs on: increase this and you won't have an issue anymore.

Re: stack/heap memory corruption?

Posted: Tue Apr 30, 2024 2:27 am
by hyuan75
Thank you @ESP_Sprite for reply, it really shocked me that other components will consumed too many stack memory - until I doubled the task stack size( from 8K to 16K), the program can run smoothly!

Re: stack/heap memory corruption?

Posted: Tue Apr 30, 2024 4:06 am
by hyuan75
The more interesting is , when I change the code in talk_to_server,

from char array definition in function (which will allocate memory from task stack):

Code: Select all

void talk_to_server(void)
{
    char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER+1] = {0};
    ...
}
to char * , which will allocate memory from heap :

Code: Select all

void talk_to_server(void)
{
    char *local_response_buffer = NULL;
    int heapleft = heap_caps_get_free_size(MALLOC_CAP_8BIT);
    ESP_LOGI(TALKTAG, "free heap before malloc :\n%d ", heapleft);
    local_response_buffer = malloc(MAX_HTTP_OUTPUT_BUFFER+ 1);
    heapleft = heap_caps_get_free_size(MALLOC_CAP_8BIT);
    ESP_LOGI(TALKTAG, "free heap after malloc :\n%d ", heapleft);
    if (NULL != local_response_buffer)
    ...
}
I still have to increase task stack size, even the heap memory is big enough to allocate, otherwise the CPU will halt still. How to explain this?