Чтобы понять использование бесплатного языка программирования C, я попытался запустить этот код на Ubuntu, но при запуске EXE файла я получаю ошибку SIGABRT. Почему программа не выходила нормально?
Ответ 3
В то время как все ответы на поведение undefined правильны, просмотр реализации может быть более полезным.
Я думаю, что очень хорошая ссылка на это K & R C malloc. Объяснение того, как это работает, находится в "Программирование Langugage" , глава 8.7.
Помните, что при просмотре кода из стандартных библиотечных функций в C у них есть реализация и спецификация, где реализация может иметь воспроизводимое поведение, которое не требуется в его спецификации.
По существу почти все реализации malloc
имеют свободный список, в котором они управляют областями свободной памяти в списке (или в нескольких списках). Свободный список часто обрабатывается таким образом, что вызов free
в области памяти несколько раз переводит этот список в неправильное состояние.
Также может быть вызвано вредоносное поведение при целенаправленном создании структур данных. Phrack имеет датированную статью о том, как вызывать выполнение кода при передаче недопустимой памяти в free
, в то время как развращает freelist.
Также можно рассмотреть другие реализации malloc (это неполный список библиотек распределения).
Ответ 7
Существуют три области, в которых переменные могут быть созданы в программе c или С++.
- глобальные или статические переменные находятся в фиксированных местах исполняемого двоичного файла.
- автоматические переменные за пределами статической области находятся в стеке
- переменные malloc'ed или calloc'ed находятся в куче.
free() - это функция, которая освобождает ранее выделенную память в куче. Указатель на память в куче возвращается malloc или аналогичными функциями. Единственный способ прочитать или записать эту память через указатель. Указатель - это адрес, а указатель * - это содержимое, указанное на этом адресе.
В показанном примере есть две переменные, определенные в Main, и эффективно статические, и возвращаемое значение Main, которое находится в стеке. Используя miniumum int, 16 бит, вот возможная карта памяти. На этой карте инструкции начинаются с 0, стек начинается с некоторого ненулевого значения (начало стека - бос) и растет с увеличением, а куча начинается с максимального адреса (... FFFF, aka -1) и растет с помощью decrememeting:
(Помните, что MIN_INT - -32768, MAX_INT - 32767... спецификация гарантирует только 16 бит, подписанный)
Каждый байт имеет адрес шириной 'n' - 16, 32 или 64 бита, обычно
-1. (начало кучи, например, 16-битный адр: 0xFFFF, 32-битный адр: 0xFFFFFFFF или 64-битный адр: 0xFFFFFFFFFFFFFFFF)
-2. (1-е место вниз от начала кучи 0x... FFFE) ptr [9], за один раз
-3. (2-е место вниз от начала кучи 0x... FFFD)
-4. (3-е место вниз от начала кучи 0x... FFFC) ptr [8], за один раз
[надрез]
-17. (16-е место с начала кучи 0x... FFEF)
-18. (17-е место вниз от начала кучи 0x... FFEE) ptr [1] за один раз
-19. (18-е место с начала кучи 0x... FFED)
-20 (положение 19 вниз с начала кучи 0x... FFEC) ptr [0], за один раз
-21. (верхняя часть кучи, 10 X 16 бит int с начала кучи 0x... FFEB), за один раз
:
Очень большой диапазон адресов на 32 или 64-битных машинах...
tos: (Top of stack 0x... tos)
bos + (sizeof (int) - 1) Конец int возвращается из Main()
bos: (начало стека: выше статических данных) Начало int, возвращаемое из Mail()
togs: (верхняя часть глобальной/статической) Конец "ptr"
: (размер указателя - ширина адресной шины... все, что требуется)
togs- (n-1): (top of global/static - (sizeof (int *) - 1)) начало "ptr"
(togs-n): Конец "ret"
(togs-n) -1: начало "ret"
(любой глобальный материал, который компилятор добавляет для себя, отладчик и т.д.)
(конец программного кода)
(начало программного кода)
(верх непрограммного кода)
0 (начало непрограммного кода, 0x... 0000)
Во время выполнения "ptr" и "ret" , вероятно, начинаются с "0", так как они фиксированные, статические, значения, считанные из файла, из которого исходит исполняемый двоичный файл.
Когда программа запускается, значение "ptr" изменяется, прежде всего, на кучу, в массиве malloc'ed из 10 ints: "0x... FFEC"
Призыв free() не изменяет значение ptr, его по-прежнему "0x... FFEC"
Free'ing "0x... FFEC" является законным и работает без каких-либо смешных событий.
Назначение "ptr = & ret" устанавливает новое значение в "ptr" , "(togs-n) -1" , начало "ret" .
Free'ing "(togs-n) -1" вызывает немедленный сбой, потому что "free" проверяет значение "(togs-n) -1" и НЕ находится в допустимом диапазоне для адреса кучи.
"ret" остается пустым, его никогда не устанавливают, но поскольку его глобальный/статический, он остается тем, что было, когда компоновщик написал его на диск.