4

私は 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 は非ゼロを 2 回返します)。

しかし、次のことを行うと(テスト目的で):

for(int32_t sz = 0x50000; sz >= 0; sz--) {
    void * mem = malloc(sz);

    if(mem != 0) {
        __BKPT();
        free(mem);

        break;
    }
}

すべてmalloc()が失敗しますmalloc(0)(つまり、__BKPT()is never reached )。そのため、実際にはヒープに割り当てられたメモリはなく(何も取得できなかったmem != 0ので、何もできませんfree())、使用可能なメモリもありません。

malloc()私は毎回失敗し、毎回sz > 0x40000成功することを期待していました(それぞれの後に正常に動作するとsz <= 0x40000仮定します)。free()malloc()

私は何かを見逃していましたか、それともこれは newlib のバグまたは意図された動作ですか?

4

2 に答える 2

6

の不適切なルーチンが原因で、ヒープ メモリ全体を割り当てるときに、 newlibmalloc()が正しく機能しません。への呼び出しが成功した後malloc_extend_top()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));

割り当てが完全に適合する場合でも、次のページ全体を割り当てようとするため、修正は常に正です。たとえば、ページ サイズが4096brk + sbrk_size = 4096*n、式4096 - ((brk + sbrk_size) & 4095)が を返す場合4096、次の空のページが必要ですが、そのためのスペースがありません。

ルーチンはこの状況を適切に処理せず、割り当てられたデータ (brk 値) だけを残すため、ヒープ全体が永続的に「解放不能」に割り当てられます。このような廃棄物 :-)

于 2016-08-22T23:13:45.123 に答える