我正在为STM32F7编写一个嵌入式软件,我的libc是newlib-2.4.0.20160527。
我已按照以下方式实施_sbrk()
:
extern intptr_t g_bss_end; /* value after the last byte in .bss */
extern intptr_t g_msp_lim; /* stack buffer starts at this address */
intptr_t _sbrk(ptrdiff_t heap_incr)
{
static intptr_t heap_end = 0;
intptr_t prev_heap_end;
intptr_t new_heap_end;
if(heap_end == 0) {
heap_end = (intptr_t)&g_bss_end;
}
prev_heap_end = heap_end;
new_heap_end = prev_heap_end + heap_incr;
if(new_heap_end >= g_msp_lim) {
errno = ENOMEM;
return -1;
}
heap_end = new_heap_end;
return prev_heap_end;
}
然后,当我执行以下操作时:
/* total capacity of my heap is 0x40000 */
void * mem = malloc(0x40000);
free(mem); mem = 0;
mem = malloc(0x40000);
一切正常(即malloc两次返回非零值)。
但是,当我执行以下操作(用于测试目的)时:
for(int32_t sz = 0x50000; sz >= 0; sz--) {
void * mem = malloc(sz);
if(mem != 0) {
__BKPT();
free(mem);
break;
}
}
每{{}}}失败,即使malloc()
(即malloc(0)
从未到达)。所以,事实上堆上没有分配的内存(我没有得到任何__BKPT()
因此我甚至不能mem != 0
某些东西)并且也没有可用的内存。
我希望每个free()
malloc()
失败并且sz > 0x40000
成功{假设sz <= 0x40000
在每个free()
之后正常工作。
我是否错过了某些内容,或者这是newlib中的错误或预期行为?
答案 0 :(得分:4)
由于malloc()
中的malloc_extend_top()
例程不正确,分配整个堆内存时,newlib的newlib/libc/stdlib/mallocr.c:2137
无法正常工作。成功拨打_sbrk()
brk = (char*)(MORECORE (sbrk_size)); /* MORECORE = _sbrk */
/* Fail if sbrk failed or if a foreign sbrk call killed our space */
if (brk == (char*)(MORECORE_FAILURE) ||
(brk < old_end && old_top != initial_top))
return;
它尝试计算校正以适应页面对齐:
/* Guarantee alignment of first new chunk made from this space */
front_misalign = (POINTER_UINT)chunk2mem(brk) & MALLOC_ALIGN_MASK;
if (front_misalign > 0)
{
correction = (MALLOC_ALIGNMENT) - front_misalign;
brk += correction;
}
else
correction = 0;
/* Guarantee the next brk will be at a page boundary */
correction += pagesz - ((POINTER_UINT)(brk + sbrk_size) & (pagesz - 1));
校正始终是正的,因为即使分配完全匹配,它也会尝试分配下一整页。例如,如果页面大小为4096
而brk + sbrk_size = 4096*n
,则表达式4096 - ((brk + sbrk_size) & 4095)
将提供4096
,因此需要下一个空白页面,但没有空间。< / p>
例程正在处理这种情况并不正确,只留下分配的数据(brk值),导致永久的“不合理”的整个堆分配。这样的浪费: - )
答案 1 :(得分:0)
经过测试,效果很好。
From 1473e08d2a16ad448afedb7036a476231a785643 Mon Sep 17 00:00:00 2001
From: Jeff Johnston <jjohnstn@redhat.com>
Date: Thu, 24 May 2018 23:53:15 -0400
Subject: [PATCH] Fix issue with malloc_extend_top
- when calculating a correction to align next brk to page boundary,
ensure that the correction is less than a page size
- if allocating the correction fails, ensure that the top size is
set to brk + sbrk_size (minus any front alignment made)
Signed-off-by: Jeff Johnston <jjohnstn@redhat.com>
---
newlib/libc/stdlib/mallocr.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/newlib/libc/stdlib/mallocr.c b/newlib/libc/stdlib/mallocr.c
index ecc445f..26d1c89 100644
--- a/newlib/libc/stdlib/mallocr.c
+++ b/newlib/libc/stdlib/mallocr.c
@@ -2198,13 +2198,18 @@ static void malloc_extend_top(RARG nb) RDECL INTERNAL_SIZE_T nb;
/* Guarantee the next brk will be at a page boundary */
correction += pagesz - ((POINTER_UINT)(brk + sbrk_size) & (pagesz - 1));
+ /* To guarantee page boundary, correction should be less than pagesz */
+ correction &= (pagesz - 1);
+
/* Allocate correction */
new_brk = (char*)(MORECORE (correction));
if (new_brk == (char*)(MORECORE_FAILURE))
{
correction = 0;
correction_failed = 1;
- new_brk = brk;
+ new_brk = brk + sbrk_size;
+ if (front_misalign > 0)
+ new_brk -= (MALLOC_ALIGNMENT) - front_misalign;
}
sbrked_mem += correction;
--
1.8.3.1