在这个简单的代码中:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
void * first = sbrk(4096);
void *p = sbrk(0);
//sigterm, however were it (p-4) -> it could be derefenced
*((int*)(p-3)) = 1;
printf("%dn",*(int*)(p-3));
}
如果我试图在堆的末尾解引用地址,我得到段错误。然而B-16(其中B代表堆中断)是可解引用的,而B-12则不是(段错误)。那么堆断点附近存储了什么信息呢?
你不是在做p-12和p-16,你在做p-3和p-4。
你正在做(int*)(p-3)
,即你减去3和,然后转换为int,而不是相反,((int*)p)-3
。因此,编译器会从声明p
指向的类型中减去3个,而不是3个int型。
该类型是void
,因为p
是void*
。所以编译器减去3个字节。然后读取4字节,因为int
在编译器上是4字节。
注意:从void*
中减去是一个特定于gcc的扩展-一个额外的功能,不是普通c的一部分。一些编译器会给你一个错误,说你不能添加或减去void*
指针。在这些编译器上,要减去3个字节,必须强制转换为char*
,然后减去3。