数据段值会破坏堆栈变量

时间:2013-09-11 02:27:26

标签: c

#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)中的值。什么是这种沉默的腐败。

2 个答案:

答案 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;

指针算法只有在指向数组的元素或者指向数组的元素时才有效,否则它是未定义的行为,就像它在这里一样。