#include <stdio.h>
#include <stdlib.h>
int main()
{
char *name;
char *command;
name=(char *)malloc(10);
command=(char *)malloc(128);
printf("address of name is : %d\n",name);
printf("address of command is:%d\n",command);
printf("Distance between addresses is :%d\n",command-name);
printf("Enter your name:");
gets(name);
printf("Hello %s\n",name);
system(command);
}
分配恒定内存量(缓冲区大小)和两个地址(相邻内存块)之间的距离有什么区别?在此示例中,name和command之间的差异为16 Bytes,name的缓冲区大小为10 Bytes。哪一个会触发缓冲区溢出?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// typedef size_t u_long;
int main(){
u_long distance;
char *buf1= (char *)malloc(16);
char *buf2= (char *)malloc(16);
distance= (u_long)buf2 - (u_long)buf1;
printf("buf1 = %p\nbuf2 = %p\ndistance = 0x%x bytes\n",
buf1, buf2, distance);
memset(buf2, 'A', 15); buf2[15]='\0';
printf("before overflow buf2 = %s\n", buf2);
memset(buf1, 'B', (8+distance));
printf("after overflow buf2 = %s\n", buf2);
return 0;
}
答案 0 :(得分:0)
由于name
和command
是通过对malloc()
的单独调用分配的,因此严格来说,他们的地址之间的差异毫无意义。指针算法仅适用于同一阵列或相同分配块中的地址。当然,减去两个指针会给你一些,你只是不能用它做任何事情。没有理由相信malloc()
将使用相邻的内存块,或者甚至后来的分配将具有比先前的更高的地址。然而,它可以自由分配它看起来合适。
您分配了10个字节,因此您可以使用10个字节。就是这样。
答案 1 :(得分:0)
当我在Mac OS X 10.8.3上使用GCC 4.7.1运行非常温和编辑的第二个程序版本时,0x%x
更改为0x%zX
并且{{1}的typedef没有注释,输出是:
u_long
这两项拨款彼此之间的距离并不遥远,这是完全允许的,但(坦率地说)不是我期望看到的。大约14 KiB的写入肯定会引发未定义的行为。
您无法假设可移植代码中的内存分配位置。如果您希望调整到buf1 = 0x7fe8d0c000e0
buf2 = 0x7fe8d0c03a00
distance = 0x3920 bytes
before overflow buf2 = AAAAAAAAAAAAAAA
Abort trap: 6
的某个特定版本,则可能会这样做,但这会限制您的可移植性。
然而,在像Mac这样的64位系统上,当你进行两个单独的1字节分配时,它们通常相隔16个字节。在您的中间添加此代码:
malloc()
给出了输出:
char *buffer[4];
for (int i = 0; i < 4; i++)
{
buffer[i] = (char *)malloc(1);
printf("buffer[%i] = %p\n", i, buffer[i]);
}
在循环中每次请求16个字节时,我也得到了相同的输出。那很有意思;这意味着没有与这些内存块直接相邻的控制信息(这些分配之间没有控制信息的空间 - 它可能存储在buf1 = 0x7fe821c000e0
buf2 = 0x7fe821c03a00
distance = 0x3920 bytes
buffer[0] = 0x7fe821c03a10
buffer[1] = 0x7fe821c03a20
buffer[2] = 0x7fe821c03a30
buffer[3] = 0x7fe821c03a40
before overflow buf2 = AAAAAAAAAAAAAAA
Abort trap: 6
和buf1
之间的某些空间中。在其他64位系统上,我看到最小分配为32字节,其中一些空间用于控制信息。也就是说,来自buf2
的1个字节的连续请求的地址将产生相隔32个字节的地址,但是对32个字节的连续请求将产生相隔64个字节的地址。
在32位Linux机器上,我有1个字节和8个字节的请求,我得到了分配:
malloc()
对于16字节的请求,我得到了:
buffer[0] = 0x804a008
buffer[1] = 0x804a018
buffer[2] = 0x804a028
buffer[3] = 0x804a038
如您所见,在第一种情况下,分配相隔16个字节;在第二个,24个字节。额外的8个字节是控制开销。
当您请求N个字节的空格并且buffer[0] = 0x804a008
buffer[1] = 0x804a020
buffer[2] = 0x804a038
buffer[3] = 0x804a050
返回指针P时,您有明确的权限来访问地址范围中的数据:
malloc()
该范围之外的任何访问都会导致未定义的行为。未定义的行为可能包括似乎正常工作。
在第一个程序中,执行 (char *)P + 0 .. (char *)P + N - 1 (inclusive)
而不初始化system(command)
指向的数据。这不太可能带来幸福。