数据段值损坏堆栈变量


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

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内部形成的裸奇点,最终吞噬地球。

底线,不要这样做:-)

int *ptr1 = malloc ( 2 );

你为一个int分配了2个字节,这在现代机器中通常至少是4个字节。

*(ptr1+2) = 0xabcd;

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

最新更新