Что произойдет, если я установлю значение вне памяти, выделенной с помощью calloc? - PullRequest
1 голос
/ 15 апреля 2019

Рассмотрим следующее:

int* x = calloc(3,sizeof(int));
x[3] = 100;

, который находится внутри функции.

Я не получаю ошибку, когда я компилирую и запускаю программу, но когда я запускаю ее с помощью valgrind, я получаю «Недопустимая запись размера 4».

Я понимаю, что я получаю доступ к месту памяти вне того, что я выделил с помощью calloc, но я пытаюсь понять, что на самом деле происходит.

Имеет ли какой-либо адрес в стеке (?) Значение 100? Потому что, безусловно, должно быть больше доступной памяти, чем то, что я выделил с помощью calloc. Является ли ошибка valgrind скорее «Эй, ты, вероятно, не хотел этого делать»?

Ответы [ 5 ]

3 голосов
/ 15 апреля 2019

Я понимаю, что я получаю доступ к месту памяти вне того, что я выделил с помощью calloc, но я пытаюсь понять, что на самом деле происходит.

"Что на самом деле происходит" - этоне четко определены;это полностью зависит от того, что перезаписывается.До тех пор, пока вы не перезаписаете ничего важного, ваш код будет отображаться , чтобы работать должным образом.

Вы можете испортить другие данные, которые были выделены динамически.Вы можете испортить какую-то кучу бухгалтерии.

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

2 голосов
/ 15 апреля 2019

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

Даже если вы идиот, я даю вам дополнительные очки за тестирование с Valgrind.

На практике, скорее всего, вы найдете значение 100 в памяти после массива.

Остерегайтесь носовых демонов .

2 голосов
/ 15 апреля 2019

Нет никаких гарантий относительно того, что было выделено в пространстве за x[3] или что будет написано там в будущем. alinsoar отметил, что x[3] само по себе не вызывает неопределенного поведения, но вы не должны пытаться получить или сохранить значение оттуда. Часто вы, вероятно, сможете писать и получать доступ к этой ячейке памяти без проблем, но написание кода, основанного на достижении за пределами выделенных вами массивов, настраивает вас на очень трудное обнаружение ошибок в будущем.

Имеет ли какой-либо адрес в стеке (?) Значение 100?

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

2 голосов
/ 15 апреля 2019

Имеет ли какой-либо адрес в стеке (?) Значение 100?

Прежде всего, calloc выделяет память в куче, а не в стеке.

Теперь об ошибке.

Конечно, большую часть времени у вас достаточно памяти, когда ваша программа работает.Однако, когда вы выделяете память для x байтов, менеджер памяти ищет какой-то свободный кусок памяти этого точного размера (+ может быть, еще больше, если calloc запрашивает больший объем памяти для хранения некоторой вспомогательной информации),нет никаких гарантий относительно того, для чего используются байты после этого чанка, и даже нет никаких гарантий, что они не предназначены только для чтения или могут быть доступны вашей программе.

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

Таким образом, к ошибке valgrind следует относиться очень серьезно.

Язык C не требует проверки границ при доступе к массиву, ибольшинство компиляторов Си не реализуют это.Кроме того, если бы вы использовали переменный размер вместо постоянного значения 3, размер массива мог бы быть неизвестен во время компиляции, и не было бы никакого способа проверить, не ограничен ли доступ.

0 голосов
/ 15 апреля 2019

Вы выделяете память для 3 целочисленных элементов, но получаете доступ к 4-му элементу (x[3]).Отсюда и предупреждающее сообщение от valgrind.Компилятор не будет жаловаться на это.

...