From: Simon Glass <simon.glass@canonical.com> Use of memalign can trigger fragmentation issues where the over-sized allocation needed to guarantee alignment fails, even though the exact user-requested size would succeed and be properly aligned. If the padded allocation fails, try allocating exactly the user's requested size. If that happens to be aligned, return it. Otherwise, try a third allocation with just enough extra space to achieve alignment. Changes from original commits: - Port to dlmalloc 2.8.6 internal_memalign() instead of mEMALIGn() - Use internal_malloc/internal_free instead of mALLOc/fREe Signed-off-by: Stephen Warren <swarren@nvidia.com> Reviewed-by: Tom Rini <trini@konsulko.com> Acked-by: Lukasz Majewski <l.majewski@samsung.com> Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> (cherry picked from 4f144a416469c6a29127b0656523ae628ea7cbaf) --- common/dlmalloc.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 268d3fea52a..5a8e463671c 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -4975,6 +4975,46 @@ static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { size_t nb = request2size(bytes); size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; mem = internal_malloc(m, req); +#ifdef __UBOOT__ + /* + * The attempt to over-allocate (with a size large enough to guarantee the + * ability to find an aligned region within allocated memory) failed. + * + * Try again, this time only allocating exactly the size the user wants. + * If the allocation now succeeds and just happens to be aligned, we can + * still fulfill the user's request. + */ + if (mem == 0) { + size_t extra, extra2; + + mem = internal_malloc(m, bytes); + /* Aligned -> use it */ + if (mem != 0 && (((size_t)(mem)) & (alignment - 1)) == 0) + return mem; + /* + * Otherwise, try again, requesting enough extra space to be able to + * acquire alignment. + */ + if (mem != 0) { + internal_free(m, mem); + /* Add in extra bytes to match misalignment of unexpanded alloc */ + extra = alignment - (((size_t)(mem)) % alignment); + mem = internal_malloc(m, bytes + extra); + /* + * mem might not be the same as before. Validate that the previous + * value of extra still works for the current value of mem. + */ + if (mem != 0) { + extra2 = alignment - (((size_t)(mem)) % alignment); + if (extra2 > extra) { + internal_free(m, mem); + mem = 0; + } + } + } + /* Fall through to original NULL check and chunk splitting logic */ + } +#endif if (mem != 0) { mchunkptr p = mem2chunk(mem); if (PREACTION(m)) -- 2.43.0