Разница между стеком и кучей - PullRequest
3 голосов
/ 23 января 2012

Скажите, пожалуйста, разницу между стеком и кучей по отношению к приведенному ниже коду

int main()
{
    int arr[3];
    int *a;

    arr [5] = 6; // out of bound but it will not give error.
    arr [3000] = 8 ; //SIGSEGV 

    a = malloc (sizeof (int));
    a[4] = 6; 
    a[4000] = 8; //No error
}

Я знаю, что arr является статическим массивом, и я получаю доступ к адресу другого процесса, когда делаю arr [3000], который выдает ошибку SIGSEGV. Но я не понимаю, почему [4000] не выдаст мне ошибку времени выполнения, то есть сигнал SIGSEGV.

Спасибо

Ответы [ 6 ]

9 голосов
/ 23 января 2012

Не гарантируется, что любой из этих вызовов на самом деле записывает в недоступную память (что может привести к возникновению ошибки). Также вероятно, что программа имеет разрешение на запись в эту память и не запускает segfault, но перезаписывает некоторые другие внутренние данные, не связанные с вашим массивом. Это, конечно, может привести к неожиданным последствиям в других местах программы.

Обычно это называется неопределенное поведение . Не дается никаких обещаний, что произойдет, когда вы запишете за пределы массива, что-то может случиться или не произойти.

3 голосов
/ 23 января 2012

Ссылка на элементы вне границ массива является неопределенным поведением, что означает, что может произойти все что угодно (исключение, исключение или другое). Причина, по которой присвоение arr[5] не привело к ошибке, возможно, заключается в том, что значение все еще находилось в допустимом стековом пространстве (но в дальнейшем это могло привести к ошибкам в более долго работающем приложении). Недопустимое присвоение выделенному массиву могло привести к записи на страницу в памяти, принадлежащей процессу, и, таким образом, не привести к ошибке. Но это может измениться от бега к бегу. И даже если адрес принадлежал странице за пределами адресного пространства процесса, от того, что на самом деле произойдет, зависит ОС.

1 голос
/ 23 января 2012

Переполнения буфера - неопределенное поведение.Переполнение буфера может произойти сбой в понедельник, если он находится в стеке и сбой в Tuedsay, если он находится в куче.Это просто неопределенное поведение.

Вот параграф C, который говорит, что это неопределенное поведение:

(C99, 6.5.6p8) "Если результат указывает на один элемент после последнего элементаобъекта массива, он не должен использоваться в качестве операнда оцениваемого унарного оператора *. "

И, конечно, [] - это замаскированный унарный оператор *:

(6.5.2.1p2) "Определение оператора нижнего индекса [] состоит в том, что E1 [E2] идентичен (* ((E1) + (E2)))."

1 голос
/ 23 января 2012
int main()
{
    int arr[3];
    int *a;

    arr [5] = 6; // out of bound but it will not give error.
// J: False - it is undefined. expect raptors, or something.

    arr [3000] = 8 ; //SEGSEV
// J: Now you see the effects of undefined behavior, even though you did not in a previous invalid access.

    a = malloc (sizeof (int));
    a[4] = 6; // J: Still undefined behavior
    a[4000] = 8; //No error
// J: Still undefined behavior
}

Но я не понимаю, почему [4000] не даст мне никакой ошибки времени выполнения, т. Е. Сегцев сигнал.

Это будет на другой платформе или архитектуре. Это действительно не имеет значения - вы всегда должны избегать UB.

В любом случае, разница заключается в реализации распределителя вашей системы (при условии, что компилятор не поместил результат malloc в стек).

То, как ваш распределитель управляет и распределяет память, является деталью реализации, на которую вы не должны полагаться, особенно когда вы бросаете UB.

Распределитель может продавать части памяти из большего физического распределения. Эта базовая реализация зависит от платформы.

1 голос
/ 23 января 2012

Все выделенные вами случаи представляют собой «неопределенное поведение».

И в некоторых случаях это просто, а в других это ошибка сегментации.

Что особенно плохо в «неопределенном поведении»в том, что он может работать, как и ожидалось, в течение некоторого времени, но затем внезапно начать производить "нежелательные побочные эффекты" (то есть ошибки сегментации).Это очень затрудняет отладку и воспроизведение этих условий в производстве.

1 голос
/ 23 января 2012

Куча - это память, из которой вы выполняете malloc () блок памяти.

a [4000] = 8;не удалось, потому что повезло, что он не попал в адрес памяти другого процесса.Это было просто случайно

...