#include <stdio.h>
main()
{
int *ptr1 = malloc ( 2 );
int *ptr2 = malloc ( 4 );
int *ptr3 = malloc ( 16 );
printf("ptr1 - %x \n", ptr1);
printf("ptr2 - %x \n", ptr2);
printf("ptr3 - %x \n", ptr3);
*ptr1 = 0x1111;
*ptr2 = 0x2222;
*ptr3 = 0x3333;
#if 1
// silent corruption...
*(ptr1+2) = 0xabcd;
#endif
#if 1
// corruption
*(ptr1+3) = 0xbeee;
#endif
{
int a;
scanf("%d", &a);
}
free(ptr1);
free(ptr2);
free(ptr3);
}
在上面的程序中,我得到ptr的地址作为ptr1,ptr2,ptr3之间的差值0f 10而不是4个字节的差值。我也在这里检查堆栈损坏。数据段(ptr1,ptr2,ptr3)中的值如何破坏堆栈段(a)中的值。什么是这种沉默的腐败。
答案 0 :(得分:5)
malloc
需要为您提供所请求的字节数(或显然为NULL),但没有规则反对为您提供更多。它通常适用于(例如) 16字节(0x10
)边界,以有效地分配内存。
这并不是说你被允许使用比你要求的更多,这是未定义的行为(UB)。
换句话说,这是不允许的:
int *ptr1 = malloc (2);
*(ptr1+3) = 0xbeee;
因为整数必须至少是字节/字符的大小所以两个字节不能给你四个整数。
所以,即使你的整数 两个字节长(而且它们现在可能不是),这个语句试图将该数组中的第四个整数设置为一个值。可以这样想(对于四字节整数):
+---------------+
ptr1 -> | You can use | \
| these 2 bytes.| \
--------------- *ptr1
| But not these | /
| two. | /
---------------
| | \
| | \*(ptr1+1)
| | /
| | /
| Nor any of | \
| these | \*(ptr1+2)
| | /
| | /
| | \
| | \*(ptr1+3)
| | /
| | /
+---------------+
ptr2 -> | |
在代码中使用魔术数字实际上是非常不寻常的(而且相当糟糕的做法),一个更好的解决方案是:
int *ptr1 = malloc (sizeof (*ptr1) * N);
获取给定数据类型的N
元素数组。
至于为什么你看到某些事情正在发生,这无关紧要。一旦你进入UB领土,所有的赌注都会被取消。 任何都可能发生,从预期的工作到在你的CPU内形成的裸体奇点,最终吞噬地球。
底线,不要这样做: - )
答案 1 :(得分:3)
int *ptr1 = malloc ( 2 );
您为int
分配2个字节,在现代机器中通常至少为4个字节。
*(ptr1+2) = 0xabcd;
指针算法只有在指向数组的元素或者指向数组的元素时才有效,否则它是未定义的行为,就像它在这里一样。