# malloc理解その2 ## やっぱり難しいヒープ ![](https://i.imgur.com/sfRDGw8.jpg) ### 用語おさらい * **chunk** => mallocで確保したメモリの単位 * **unsorted_bin** * **small_bin** * **large_bin** => mallocが確保したメモリを管理しておくためのリスト * **arena** => binの管理領域 ___ ## malloc()についての理解 ``` c void *malloc(size_t size); sizeバイトのメモリ"領域を確保して先頭ポインタ"を返す つまり ptr = maloc(size) ``` <br> 目的: ユーザが使うためのメモリを確保する 種別: libcのライブラリに実装されている(system関数ではない) #include <stdlib.h>とすることで利用できるようになる。 ここでmallocの使いかたを見てみましょう。 ``` c [file1.c] char *str; str = (char *)malloc(100); //変数strに100byteの領域割当 fgets(str); ``` 上記のように記述すると、`str`で100byte分の領域を確保(利用)することができます。 #### 気を付けるポイント: ただし、意識しておけなければならないこととして、上記の場合、mallocで確保したstrは |malloc構造体|strの利用できる領域| --|-- |16byte| 100byte が確保されます。 ___ ## free()についての理解 ``` c void free(void *ptr) malloc等で確保した領域のポインタを渡すと領域を解放する。 つまりfree(ptr) ``` 目的: mallocで確保したメモリを解放する 種別: libcのライブラリに実装されている(system関数ではない) ``` c [file1.c]↑の続き free(str) //変数strの領域をfree listにつなぐ ``` #### 重要ポイント **free()したメモリは、ゼロクリアされずfree listに繋がれるだけ。** メモリの中身はそのまま残っている。(保証はされない) ___ ### なぜゼロクリアされないのか 結論: mallocを管理するのに使っちゃってるから 下記はmalloc構造体のソースコードです。 ``` c struct malloc_chunk { INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */ INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */ struct malloc_chunk* fd; /* double links -- used only if free. */ struct malloc_chunk* bk; /* Only used for large blocks: pointer to next larger size. */ struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */ struct malloc_chunk* bk_nextsize; }; ``` ![](https://i.imgur.com/csDTITb.jpg) <div style="text-align:center">1.ヒープ図</div></br> 青枠のmalloc領域をfreeする場合に、free(*ptr)は青枠内のsizeを参照してどこまで解放すればよいのかを判断します。そうすることで、青枠のすぐ上のsizeまで解放しますが、freeとして開放されているので、もう使われていないという前提で勝手にfree listのためのmalloc_chunckメンバとして利用します。 mallocで確保されたメモリは、chunkという単位でarenaという領域にリストされます。freeされた場合は、free listに繋がれますが、リストの性質上、前の要素のアドレスを保持しておく必要があるため`fd`と`bk`が存在します。 ちなみにそれぞれの意味は... `fd` -> `forward pointer` `bk` -> `backword pointer` イメージ図 ``` forward links --> _(fd)_ _(fd)_ / \ / \ _(fd)-> NULL / V / V / head ---> item1 item2 item3 / ^ / ^ / NULL <-(bk)_/ \_(bk)_/ \_(bk)_/ <-- backward links ``` また、上記「1.ヒープ図」でsizeメンバの末尾にビットが0/1で記載されているのには理由があります。sizeメンバの値は常に8の倍数になるため、下位3bitは使われないのです。 そのため、使っていないbitを一つ前のchunckが使用しているかどうかを表すフラグを立てることにより、メモリの効率化を図っているようです。 ![](https://i.imgur.com/0CbdKuM.gif) ___ ### small bin 大きさがバラバラだと確保しにくいという思想より、16, 24, 32byteに収まるchunkを管理するためのリスト ![](https://i.imgur.com/AoxYXOG.jpg) ### large bin small binでは確保しきれない領域を格納するためにより大きい区切りにされたchunkのリスト ![](https://i.imgur.com/PZI4g5A.jpg) 上記のsmall binにも large binにも収まりきらないものはリストにつながれずmmapされます。 あれ...? そうするとfreeするときはどうなるんだろう。。 =>次の機会へ ___ ### ここで前回のおさらい ``` c #include <stdio.h> #include <stdlib.h> int main(){ puts("\n[+] allocate p1, p2, p3"); char *p1 = malloc(0x80); char *p2 = malloc(0x90); char *p3 = malloc(0xa0); printf("p1 = %p\n", p1); printf("p2 = %p\n", p2); printf("p3 = %p\n", p3); puts("\n[+] free p2"); free(p2); puts("\n[+] 解放したp2と同じサイズをp4に割り当て"); char *p4 = malloc(0x90); printf("p4 = %p\n", p4); return 0; } ``` ↓ ``` sh vagrant@ubuntu-xenial:/vagrant_data$ ./malloc [+] allocate p1, p2, p3 p1 = 0x602420 p2 = 0x6024b0 p3 = 0x602550 \n[+] free p2 [+] 解放したp2と同じサイズをp4に割り当て p4 = 0x6024b0 # ここがp2と同じ値やんけ!!! vagrant@ubuntu-xenial:/vagrant_data$ ``` mallocに同じサイズのメモリを要求した場合に、同じ領域が利用されるということがわかりました。 mallocで確保した領域とメモリダンプの幅が異なることから、malloc時にメンバ変数分のメモリも確保していることがわかります。 `char *p1 = malloc(0x80); # メモリダンプ:0x602420` `char *p1 = malloc(0x90); # メモリダンプ:0x6024b0` 0x602420 + 0x80 = 0x6024A0 ## Use After Free 話を少し戻して、同じメモリを参照するようなプログラムがあれば。。 ``` c #include <stdio.h> #include <stdlib.h> struct USER { int age; }; int main(){ puts("\n[+] memory allocate user1."); struct USER *user1; user1 = malloc(0x11);//17byteを確保 user1->age = 26; printf("user1: %p\n", user1); printf("user1->age: %d\n", user1->age); free(user1); puts("\n[+]free user1\n"); //user1を Free() printf("user1: %p\n", user1); user1->age = 30;//use after free puts("\n[+] memory allocate user2."); struct USER *user2; user2 = malloc(0x10); printf("user2: %p\n", user2); printf("user2->name: %d\n", user2->age); return 0; } ``` ↓ ``` [+] memory allocate user1. user1: 0x602420 user1->age: 26 [+]free user1 user1: 0x602420 [+] memory allocate user2. user2: 0x602420 user2->name: 30 ``` free後の変数だろうと利用できるということがわかりました。 (実際はこんなに簡単ではない) ### 引用 * maloc動画 https://www.youtube.com/watch?v=0-vWT-t0UHg * qiita https://qiita.com/kaityo256/items/94a84dbe922eb5996a27