1

calloc()以下のコードを使用して、割り当てられたメモリの最初の2/4バイトにサイズを格納することにより、割り当てられたヒープメモリのトレースを保持できるようにラッパーを作成しようとしています。私がこれだけをテストしたとき、それは大丈夫のようです。しかし、これをシステムとして置き換えると、問題が発生します。多くのヒープが利用可能であっても、場合によってcalloc()は返されることを意味します。NULL

IARコンパイラを使用してARMボードでこれを実行しています。

void *MyCalloc(size_t size) {
    size_t new_size = ((size + 3) & ~0x3); 
    size_t *result = calloc(1,new_size + sizeof(size_t)); 
    if ( result ) { 
        printf("MyCalloc addr: %p\n", result);
        *result = (new_size + sizeof(size_t));
        result = result + sizeof(size_t);
    } 
return result;
}

これが問題を引き起こしている理由は何ですか?

4

2 に答える 2

5

あなたの問題はこの行です:

result = result + sizeof(size_t);

ポインターを追加すると、数値にポインターのサイズが暗黙的に乗算されます。それで

result = result + 1;

sizeof(size_t)結果ポインタをバイト単位で前方に移動します。どちらが欲しいのか。なぜなら

result = result + sizeof(size_t);

結果ポインタをsizeof(size_t) * sizeof(size_t)バイト単位で前方に移動します。

このため、resultポインタが正しい場所を指していないため、呼び出し元のコードは割り当てられたバッファの終わりをオーバーフローし、ヒープを破壊します。

于 2013-02-16T18:36:56.430 に答える
5

コードにはいくつかの問題があります。

  1. ヒープ関数またはヒープラッパーを作成するときは、ヒープヘッダーを格納するためにポインター演算を使用しないでください。構造を使用します。それが彼らの目的です。

  2. コードに整数のオーバーフローのバグをいくつか導入しました。誰かがあなたcalloc()に0xfffffffeバイトを要求した場合、あなたはそれらに4バイトを返します。その割り当てに4バイトを超える書き込みを行うと、ヒープオーバーフローが発生します。

  3. あなたcalloc()はと同じ署名を持っていませんcalloc()。交換方法によってはcalloc()、これが問題になる可能性があります。

  4. calloc()malloc()整列されたポインタを自然に返します。x86では、少なくとも8バイトにアラインされたアプリケーションへのポインターを返す必要があり、x64では、少なくとも16バイトにアラインされたポインターを返す必要があります。

    コードでは、実際のcallocを使用して「重いリフティング」(つまり「rawアロケータ」として)を実行しています。これは問題なく、8バイトまたは16バイトの整列されたポインターを返しますが、ポインターを返すとその構造に4バイト入ると、callocは呼び出し元に整列されていないポインターを返すことになり、calloc置換を呼び出す人々に問題を引き起こす可能性があります。

次のようなコードをもう少し試してください。

 typedef struct 
 {
    size_t cbSize;
 } MyAwesomeHeapHeader;
 // TODO: ensure that MyAwesomeHeapHeader is 8-byte aligned on x86 and 16-byte aligned on x64 (or just 16-byte aligned on both).

 void* MyAwesomeMalloc(size_t cbSize)
 {
    MyAwesomeHeapHeader* header;
    void* internalAllocatorPtr;
    size_t cbAlloc;
    // TODO: Maybe I want a heap footer as well?

    // TODO: I should really check the following for an integer overflow:
    cbAlloc = sizeof(MyAwesomeHeapHeader) + cbSize; 
    internalAllocatorPtr = MyAwesomeRawAllocator(cbAlloc); // at the moment you're using the real calloc for this, but you could use malloc or write your own raw allocator
    // TODO: Check for null

    header = (MyAwesomeHeapHeader*)internalAllocatorPtr;
    header->heapSize = cbSize;
    // TODO: other fields here.

    return (uint8_t*)(internalAllocatorPtr) + sizeof(MyAwesomeHeapHeader);
 }
于 2013-02-16T18:59:16.963 に答える