Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

heap_caps_malloc(n, MALLOC_CAP_EXEC) returns non-executable RAM on ESP32-S2 (IDFGH-14012) #14835

Closed
3 tasks done
projectgus opened this issue Nov 6, 2024 · 4 comments
Closed
3 tasks done
Assignees
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Bug bugs in IDF

Comments

@projectgus
Copy link
Contributor

projectgus commented Nov 6, 2024

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

v5.2.3, and master (v5.4-dev-4076-gce6085349f)

Espressif SoC revision.

ESP32-S2

Operating System used.

Linux

How did you build your project?

Command line with idf.py

If you are using Windows, please specify command line type.

None

Development Kit.

ESP32-S2-Saola

Power Supply used.

USB

What is the expected behavior?

heap_caps_malloc(n, MALLOC_CAP_EXEC) should return NULL or memory which is executable.

What is the actual behavior?

It seems RTC FAST memory is added to the executable heap space but the address returned is the Data Bus mapping not the Instruction Bus mapping.

Steps to reproduce.

  1. Copy the following C code into an example:
#include <stdio.h>
#include <inttypes.h>
#include "esp_memory_utils.h"
#include "esp_heap_caps.h"

void leak_pointer(void * arg)
{
    // Keep the compiler happy by leaking memory to here
}

void app_main(void)
{
    heap_caps_print_heap_info(MALLOC_CAP_EXEC);
    while (1) {
        void *p = heap_caps_malloc(2048, MALLOC_CAP_EXEC);
        printf("Alloced %p\n", p);
        if (p == NULL) {
            printf("Out of executable RAM, woohoo!\n");
            return;
        }
        if (!esp_ptr_executable(p)) {
            printf("Got non-executable pointer back :(\n");
            return;
        }
        leak_pointer(p);
    }
}
  1. idf.py set-target esp32s2
  2. idf.py menuconfig and set ESP_SYSTEM_MEMPROT_FEATURE to n (to allow executable heap)
  3. idf.py flash monitor

Debug Logs.

I (23) boot: ESP-IDF v5.4-dev-4076-gce6085349f-dirty 2nd stage bootloader
I (24) boot: compile time Nov  6 2024 15:02:57
I (24) boot: chip revision: v0.0
I (26) boot: efuse block revision: v0.1
I (30) boot.esp32s2: SPI Speed      : 80MHz
I (34) boot.esp32s2: SPI Mode       : DIO
I (38) boot.esp32s2: SPI Flash Size : 2MB
I (41) boot: Enabling RNG early entropy source...
I (46) boot: Partition Table:
I (48) boot: ## Label            Usage          Type ST Offset   Length
I (55) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (61) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (68) boot:  2 factory          factory app      00 00 00010000 00100000
I (74) boot: End of partition table
I (78) esp_image: segment 0: paddr=00010020 vaddr=3f000020 size=08ef8h ( 36600) map
I (92) esp_image: segment 1: paddr=00018f20 vaddr=3ff9e010 size=0001ch (    28) load
I (93) esp_image: segment 2: paddr=00018f44 vaddr=3ffbf950 size=01bf0h (  7152) load
I (101) esp_image: segment 3: paddr=0001ab3c vaddr=40024000 size=054dch ( 21724) load
I (113) esp_image: segment 4: paddr=00020020 vaddr=40080020 size=13304h ( 78596) map
I (130) esp_image: segment 5: paddr=0003332c vaddr=400294dc size=06468h ( 25704) load
I (142) boot: Loaded app from partition at offset 0x10000
I (142) boot: Disabling RNG early entropy source...
I (152) cache: Instruction cache        : size 8KB, 4Ways, cache line size 32Byte
I (152) cache: Data cache               : size 8KB, 4Ways, cache line size 32Byte
I (167) cpu_start: Unicore app
I (174) cpu_start: Pro cpu start user code
I (174) cpu_start: cpu freq: 160000000 Hz
I (174) app_init: Application information:
I (174) app_init: Project name:     hello_world
I (178) app_init: App version:      v5.4-dev-4076-gce6085349f-dirty
I (184) app_init: Compile time:     Nov  6 2024 15:03:00
I (189) app_init: ELF file SHA256:  bea6b51e6...
I (194) app_init: ESP-IDF:          v5.4-dev-4076-gce6085349f-dirty
I (200) efuse_init: Min chip rev:     v0.0
I (204) efuse_init: Max chip rev:     v1.99 
I (208) efuse_init: Chip rev:         v0.0
I (212) heap_init: Initializing. RAM available for dynamic allocation:
I (218) heap_init: At 3FFC1D58 len 0003A2A8 (232 KiB): RAM
I (223) heap_init: At 3FFFC000 len 00003A10 (14 KiB): RAM
I (228) heap_init: At 3FF9E02C len 00001FBC (7 KiB): RTCRAM
I (234) spi_flash: detected chip: generic
I (237) spi_flash: flash io: dio
W (240) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (253) main_task: Started on CPU0
I (253) main_task: Calling app_main()
Heap summary for capabilities 0x00000001:
  At 0x3ffc1d58 len 238248 free 228728 allocated 8420 min_free 228728
    largest_free_block 221184 alloc_blocks 40 free_blocks 1 total_blocks 41
  At 0x3fffc000 len 14864 free 14448 allocated 0 min_free 14448
    largest_free_block 14336 alloc_blocks 0 free_blocks 1 total_blocks 1
  At 0x3ff9e02c len 8124 free 7744 allocated 0 min_free 7744
    largest_free_block 7680 alloc_blocks 0 free_blocks 1 total_blocks 1
  Totals:
    free 250920 allocated 8420 min_free 250920 largest_free_block 221184
Alloced 0x40034290
Alloced 0x40034b14
Alloced 0x40035398
... Skip many similar lines out of output
Alloced 0x4006e5b8
Alloced 0x4006eebc
Alloced 0x3ff9e1ac
Got non-executable pointer back :(
I (493) main_task: Returned from app_main()

Done

More Information.

While running the test program above on other SoCs to see if the problem is only on ESP32-S2 I noticed this output with original ESP32 running on v5.2.3 and the master branch:

... Skip early output
I (191) app_init: Application information:
I (194) app_init: Project name:     hello_world
I (199) app_init: App version:      v5.4-dev-4076-gce6085349f-dirty
I (206) app_init: Compile time:     Nov  6 2024 15:01:23
I (212) app_init: ELF file SHA256:  9b90875fc...
I (217) app_init: ESP-IDF:          v5.4-dev-4076-gce6085349f-dirty
I (224) efuse_init: Min chip rev:     v0.0
I (229) efuse_init: Max chip rev:     v3.99 
I (234) efuse_init: Chip rev:         v3.0
... Skip lines of expected output
Alloced 0x4009e7b0
Alloced 0x4009efb4
Alloced 0x4009f7b8
Alloced 0x400bf21c
Got non-executable pointer back :(
I (420) main_task: Returned from app_main()

Done

It seems like esp_ptr_executable(0x400bf21c) is false. According to the TRM this is the "Remap" region of "Internal SRAM 1", so I'm not sure if the bug here is that this address should not be returned for MALLOC_CAP_EXEC or that esp_ptr_executable() is returning false for an executable address. I can open a second issue for this if it is helpful.

@projectgus projectgus added the Type: Bug bugs in IDF label Nov 6, 2024
@github-actions github-actions bot changed the title heap_caps_malloc(n, MALLOC_CAP_EXEC) returns non-executable RAM on ESP32-S2 heap_caps_malloc(n, MALLOC_CAP_EXEC) returns non-executable RAM on ESP32-S2 (IDFGH-14012) Nov 6, 2024
@espressif-bot espressif-bot added the Status: Opened Issue is new label Nov 6, 2024
@projectgus
Copy link
Contributor Author

Alloced 0x400bf21c
Got non-executable pointer back :(
I (420) main_task: Returned from app_main()

For this ESP32 case mentioned in the "More Information", it seems like 0x400bf21c is executable[^] so the bug is in esp_ptr_executable() returning false. Should I open a new issue for this?

[^] Verified by running the test code from #14836

@SoucheSouche
Copy link
Collaborator

Hi @projectgus, thanks for reporting this.

I found and fixed the issue. In the memory_layout.c file of the esp32s2, the IRAM starting address for the RTC entry in the soc_memory_regions array was not set properly.
Additionally, the heap component allocating functions were only checking for DIRAM memory type to return an IRAM address to the user when MALLOC_CAP_EXEC was set in the caps.

I will have a look at #14836 next. I thought both would be related but after briefly checking the issue on C6 you mentioned, it doesn't seem to be directly related to this issue.

Concerning #14837, I have an ongoing MR that makes your idea straightforward to implement. I will try to update it to make non exec heap a compile time error.

I will let you know about the status of each reported issue in their respective ticket from now on.

@espressif-bot espressif-bot added Status: Reviewing Issue is being reviewed and removed Status: Opened Issue is new labels Nov 11, 2024
@projectgus
Copy link
Contributor Author

Hi @SoucheSouche, thanks for the very quikc follow-up and sorry it took me a little while to get back to you.

Is there any chance this fix will be backported? (We ran into it on 5.2.2 but even 5.3 would be appreciated!)

@SoucheSouche
Copy link
Collaborator

Hi @projectgus, the fix for this issue is under review.

@espressif-bot espressif-bot added Status: Done Issue is done internally Resolution: NA Issue resolution is unavailable and removed Status: Reviewing Issue is being reviewed labels Dec 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Bug bugs in IDF
Projects
None yet
Development

No branches or pull requests

3 participants