要解决这个问题,你应该对glibc malloc 机制有所了解。如果您对此一无所知,可以阅读本文以了解 glibc malloc。
Glibc 使用bin来管理您释放的块,以避免频繁的系统调用。由于更频繁地分配和释放小内存空间这一事实,glibc 使用快速 bin(等距单链表)来管理小于global_max_fast(默认 64B 或 128B)的内存空间。glibc 所做的是将您释放的块的fd设置为指向快速 bin 指向的位置,并让快速 bin 指向该块。
free() 使用下一个相邻块的PREV_INUSE位来检查一个块是否被释放。但是,当您释放的块被添加到快速箱时,glibc 不会设置PREV_INUSE位。有一段代码可以检查一个fast bin的指针是否与你释放的chunk的指针相同。如果是,程序损坏,所以你不能释放一个指针两次,但你可以释放两个指针反过来。这里有一个简单的图表来帮助你理解。
当您有空时(a):
+++++++++++++++++++++++
+ 16 + 24 + 32 + ...
+++++++++++++++++++++++
|
|
|
|
+--->+--------+
|prevsize|
+--------+
| size |
+--------+
|fd=NULL |
+--------+
| ... |
+--------+
当你有空时(b):
+++++++++++++++++++++++
+ 16 + 24 + 32 + ...
+++++++++++++++++++++++
|
|
|
|
| +--------+<---------+
| |prevsize| |
| +--------+ |
| | size | |
| +--------+ |
| |fd=NULL | |
| +--------+ |
| | ... | |
+--->+--------+ |
|prevsize| |
+--------+ |
| size | |
+--------+ |
| fd |----------+
+--------+
| ... |
+--------+
当您再次释放(a)时:
+++++++++++++++++++++++
+ 16 + 24 + 32 + ...
+++++++++++++++++++++++
|
|
|
|
+--->+--------+<---------+
|prevsize| |
+--------+ |
| size | |
+--------+ |
| fd |---+ |
+--------+ | |
| ... | | |
+--------+<--+ |
|prevsize| |
+--------+ |
| size | |
+--------+ |
| fd |----------+
+--------+
| ... |
+--------+