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.c:heap_caps_get_largest_free_block() returns incorrect value (IDFGH-6129) #7808

Closed
glenn20 opened this issue Nov 1, 2021 · 4 comments
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally

Comments

@glenn20
Copy link

glenn20 commented Nov 1, 2021

Environment

  • Module or chip used: ESP32-WROOM-32D
  • IDF version(s): v4.2.1, v4.2.2, release/v4.4, v5.0-dev-79-gbcbef9a8db
  • Build System: idf.py
  • Compiler version: 8.4.0
  • Operating System: Linux
  • Power Supply: USB

Problem Description

heap_caps_get_largest_free_block(MALLOC_CAP_8BIT) always returns a value which is the largest available allocatable block rounded down to the nearest power of 2. This is in contradiction with the documentation and the semantics prior to implementation of the TLSF allocator.

The error arises from this line in the multi_heap_get_info_impl() function:

    info->largest_free_block = info->largest_free_block ? 1 << (31 - __builtin_clz(info->largest_free_block)) : 0;

The semantics of this function were changed in commit bd9b921713d80 in October 2020 as part of the implementation of the TLSF allocator. (See multi_heap.c:L374)

This bug has a significant impact on the Micropython port to all ESP32 platforms by significantly reducing the amount of RAM available to the Micropython heap when built against any IDF version since the TLSF allocator was implemented.

Expected Behavior

heap_caps_get_largest_free_block(MALLOC_CAP_8BIT) should return the size of the largest allocatable block - in agreement with the documentation and the semantics prior to implementation of the TLSF allocator.

Actual Behavior

heap_caps_get_largest_free_block(MALLOC_CAP_8BIT) returns the size of the largest allocatable block rounded down to the nearest power of 2.

@espressif-bot espressif-bot added the Status: Opened Issue is new label Nov 1, 2021
@github-actions github-actions bot changed the title heap_caps.c:heap_caps_get_largest_free_block() returns incorrect value heap_caps.c:heap_caps_get_largest_free_block() returns incorrect value (IDFGH-6129) Nov 1, 2021
@igrr
Copy link
Member

igrr commented Nov 1, 2021

@glenn20 Thanks for reporting the issue. We did run into the same issue recently, and there is a fix submitted for this internally. Please try changing that line as follows:

    if (info->largest_free_block) {
        uint32_t sl_interval = (1 << (31 - __builtin_clz(info->largest_free_block))) / SL_INDEX_COUNT;
        info->largest_free_block = info->largest_free_block & ~(sl_interval - 1);
    }

@glenn20
Copy link
Author

glenn20 commented Nov 1, 2021

@igrr I can confirm that fix works for me and resolves the issue for the Micropython ESP32 port. Will this fix be applied to updated v4.XX release tags, or only to future v5.X releases?

@igrr
Copy link
Member

igrr commented Nov 4, 2021

Should be fixed on master branch in 0028e2c, we will backport to release branches as well.

@espressif-bot espressif-bot added Resolution: Done Issue is done internally Status: Done Issue is done internally and removed Status: Opened Issue is new labels Nov 4, 2021
@glenn20 glenn20 closed this as completed Nov 16, 2021
@philippe44
Copy link

Thanks for fixing that - Took me a while to figure out because I was trying to reserve 65535 bytes for DMA. Because of this issue, it split the block in two, but ended creating a pool of 65524 and ... trying to create another of 11 which failed obviously!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Done Issue is done internally Status: Done Issue is done internally
Projects
None yet
Development

No branches or pull requests

4 participants