2013-09-11 3 views
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 как разность 0f 10 между ptr1, ptr2, ptr3 вместо разницы 4 байта. Также я проверяю повреждение стека здесь. Как значения в сегменте данных (ptr1, ptr2, ptr3) разрушают значение в сегменте стека (a) здесь. И что это за безмолвная коррупция.Значения сегментов данных, искажающие переменные стека

ответ

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, все ставки отключены. Может случиться что-нибудь из, от того, что работает, как ожидается, до обнаженной сингулярности, образующейся внутри вашего процессора, которая в конечном итоге поглощает Землю.

Итог, не делайте этого :-)

+0

+1 только для искусства ascii (woot!). (и, конечно, за действительный ответ). – WhozCraig

3
int *ptr1 = malloc (2); 

Вы отводите 2 байта в течение int, который обычно по меньшей мере, 4 байта в современной машине.

*(ptr1+2) = 0xabcd; 

Арифметика указателей действует только тогда, когда они указывают на элементы массива или один мимо него, в противном случае это неопределенное поведение, так как именно здесь.

+0

+1 Это не единственный. – WhozCraig

+0

Я вижу кучу коррупции. Существует ли коррупция стека? –

+0

@CharlieBurns не то, что я вижу, но код в блоке «безмолвная коррупция» явно выходит из диапазона. Тот, который я не думаю, что ожидаемый OP был тем, о котором упомянул Ю, и быстрая проверка 'sizeof (int)', по всей вероятности, подтвердит это. – WhozCraig

Смежные вопросы