1
#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 のアドレスを、差分 4 バイトではなく、ptr1、ptr2、ptr3 間の差分 0f 10 として取得します。また、ここでスタックの破損をチェックしています。データ セグメント (ptr1、ptr2、ptr3) の値は、スタック セグメント (a) の値をどのように破壊しますか。そして、この静かな腐敗は何ですか。

4

2 に答える 2

5

malloc要求したバイト数 (または明らかに NULL) を提供する必要がありますが、それ以上のバイト数を提供することに対するルールはありません通常、(たとえば) 16 バイト ( 0x10) 境界で機能して、メモリを効率的に割り当てます。

それは、要求した以上のものを使用することが許可されているということではありません。それは未定義の動作 (UB) です。

つまり、これは許可されていません。

int *ptr1 = malloc (2);
*(ptr1+3) = 0xbeee;

整数は少なくともバイト/文字のサイズでなければならないため、2 バイトで 4 つの整数を与えることはできません。

したがって、整数の長さが2 バイトだったとしても (現在はおそらくそうではありません)、このステートメントはその配列の4 番目の整数を値に設定しようとしています。このように考えてください (4 バイト整数の場合):

        +---------------+
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 内で形成される裸の特異点まで、あらゆることが起こり得ます。

要するに、それをしないでください:-)

于 2013-09-11T02:41:26.220 に答える
3
int *ptr1 = malloc ( 2 );

に 2 バイトを割り当てていますがint、これは通常、最新のマシンでは少なくとも 4 バイトです。

*(ptr1+2) = 0xabcd;

ポインター演算は、それらが配列の要素またはそれを超える要素を指している場合にのみ有効です。それ以外の場合は、ここにあるように未定義の動作です。

于 2013-09-11T02:29:44.990 に答える