问题描述
我有一个目标 (Stm32f030R8),我正在使用 FreeRTOS 和 newlib 可重入堆实现 (http://www.nadler.com/embedded/newlibAndFreeRTOS.html)。除了实现实际的 FreeRTOS 内存分配垫片外,此垫片还定义了 sbrk。该项目使用 GNU ARM GCC 并使用 --specs=nosys.specs 构建。
对于以下示例,FreeRTOS 尚未启动。 malloc 之前没有被调用过。 mcu 刚刚启动,只是将初始化数据从闪存复制到内存中,并配置时钟和基本外设。
只需在我的项目中使用 lib,我就会看到 sbrk 被调用时使用了非常大的增量值,用于看似很小的 malloc 调用。
目标有 8K 的内存,其中我有 0x12b8(堆开始和 ram 结束(栈顶)之间约 4KB 字节)。
我看到如果我用 str = (char*) malloc(1000);
分配 1000 个字节,sbrk 会被调用两次。首先使用 0x07e8 的增量值,然后再次使用 0x0c60 的增量值。结果是所需的总增量计数为 0x1448(5192 字节!),当然这不仅会溢出堆栈,还会溢出可用内存。
这到底是怎么回事?为什么 malloc 使用这些巨大的增量值来实现如此相对较小的所需缓冲区分配?
解决方法
我认为可能无法明确回答,而不仅仅是就调试提供建议。最简单的解决方案是单步执行分配代码以确定分配大小请求在哪里以及为什么被破坏(看起来是这样)。您当然需要从源代码构建库,或者至少在代码中包含 mallocr.c 以覆盖任何静态库实现。
在 Newlib Nano 中,对 _sbrk_r
的调用堆栈相当简单(与常规 Newlib 相比)。增量由 nano-mallocr.c 中 s
中的分配大小 nano_malloc()
确定,如下所示:
malloc_size_t alloc_size;
alloc_size = ALIGN_TO(s,CHUNK_ALIGN); /* size of aligned data load */
alloc_size += MALLOC_PADDING; /* padding */
alloc_size += CHUNK_OFFSET; /* size of chunk head */
alloc_size = MAX(alloc_size,MALLOC_MINCHUNK);
然后如果在空闲列表中没有找到一块 alloc_size
(当 free()
没有被调用时总是这种情况),那么 sbrk_aligned( alloc_size )
被调用,它调用 _ sbrk_r()
。填充、对齐或最小分配宏都没有添加如此大的数量。
sbrk_aligned( alloc_size )
会调用 _sbrk_r
。第二个调用不应大于 CHUNK_ALIGN
- (sizeof(void*)
)。
在调试器中,您应该能够检查调用堆栈或单步执行调用以查看参数不正确的位置。