Почему точно разве я не должен называть свободным () на переменных не выделенный malloc ()?

Я считал где-нибудь, что это имеет катастрофические последствия для использования free избавиться от объекта, не созданного путем вызова malloc, действительно ли это верно? почему?

9
задан sharptooth 22 April 2010 в 05:33
поделиться

7 ответов

Это неопределенное поведение - никогда не пробуйте.

Давайте посмотрим, что произойдет, когда вы попытаетесь free () автоматическую переменную. Менеджер кучи должен будет определить, как стать владельцем блока памяти. Для этого придется либо использовать какую-то отдельную структуру, в которой перечислены все выделенные блоки, которая очень медленная и редко используется, либо надеяться, что необходимые данные находятся в начале блока.

Последний используется довольно часто, и вот как я должен работать. Когда вы вызываете malloc (), диспетчер кучи выделяет блок немного большего размера, сохраняет служебные данные в начале и возвращает указатель смещения. Что-то вроде:

void* malloc( size_t size )
{
      void* block = tryAlloc( size + sizeof( size_t) );
      if( block == 0 ) {
          return 0;
      }
      // the following is for illustration, more service data is usually written
      *((size_t*)block) = size;
      return (size_t*)block + 1;
 }

, тогда free () попытается получить доступ к этим данным, смещая переданный указатель, но если указатель указывает на автоматическую переменную, любые данные будут расположены там, где он ожидает найти служебные данные. Следовательно, неопределенное поведение. Часто служебные данные модифицируются с помощью free () , чтобы менеджер кучи стал владельцем блока - поэтому, если переданный указатель относится к автоматической переменной, некоторая несвязанная память будет изменена и прочитана.

Реализации могут отличаться, но вы никогда не должны делать каких-либо конкретных предположений. Вызывайте free () только для адресов, возвращаемых функциями семейства malloc () .

15
ответ дан 4 December 2019 в 06:19
поделиться

Это неопределенное поведение. И логически, если поведение не определено, вы не можете быть уверены в том, что произошло, и правильно ли работает программа.

6
ответ дан 4 December 2019 в 06:19
поделиться

Строго говоря, это не так. calloc () и realloc () также являются действительными источниками объектов для free (). ;)

3
ответ дан 4 December 2019 в 06:19
поделиться

Несомненно, возможно для реализации malloc / free для хранения списка выделенных блоков памяти, и в случае, если пользователь пытается освободить блок, которого нет в этом списке, ничего не предпринимает.

Однако, поскольку в стандарте сказано, что это не является обязательным требованием, большая часть реализации будет рассматривать все указатели, которые становятся свободными, как действительные.

0
ответ дан 4 December 2019 в 06:19
поделиться

Посмотрите, что означает неопределенное поведение . malloc () и free () в соответствующей размещенной реализации C построены в соответствии со стандартами. В стандартах указано поведение вызова free () для блока кучи, который не был возвращен malloc () (или чем-то, что его обертывает, например calloc () ) не определено.

Это означает, что он может делать все, что вы хотите , при условии, что вы вносите необходимые изменения в free () самостоятельно. Вы не нарушите стандарт, сделав поведение free () на блоках, не выделенных malloc () согласованными и даже, возможно, ] полезный .

Фактически, могут быть платформы, которые (сами) определяют это поведение. Не знаю, но могут быть. Существует несколько реализаций malloc () для сбора / записи мусора, которые могут позволить более изящно выходить из строя при регистрации события. Но это реализация , а не поведение, определяемое стандартами .

Неопределенное просто означает, что нельзя рассчитывать на какое-либо согласованное поведение, если вы не реализуете его самостоятельно , не нарушая какого-либо определенного поведения . Наконец, реализация, определенная , не всегда означает определенную хост-системой. Многие программы связываются (и поставляются) с uclibc . В этом случае реализация является автономной, согласованной и переносимой.

1
ответ дан 4 December 2019 в 06:19
поделиться

Некоторые люди указали здесь, что это «неопределенное поведение». Я собираюсь пойти дальше и сказать, что в некоторых реализациях это приведет либо к сбою вашей программы, либо к повреждению данных. Это связано с тем, как реализованы malloc и free.

Одним из возможных способов реализации malloc / free является размещение небольшого заголовка перед каждой выделенной областью. В области malloc'd этот заголовок будет содержать размер области. Когда регион освобождается, этот заголовок проверяется, и регион добавляется в соответствующий список фрилансеров. Если это случилось с вами, это плохие новости. Например, если вы освобождаете объект, размещенный в стеке, часть стека внезапно оказывается в свободном списке. Затем malloc может вернуть эту область в ответ на будущий вызов, и вы начнете набрасывать данные по всему стеку. Другая возможность состоит в том, что вы освобождаете строковую константу. Если эта строковая константа находится в памяти только для чтения (а это часто бывает), эта гипотетическая реализация вызовет segfault и выйдет из строя либо после более позднего malloc, либо когда free добавляет объект в свой список freelist.

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

5
ответ дан 4 December 2019 в 06:19
поделиться

По стандарту это «неопределенное поведение», то есть «все может случиться». Хотя обычно это плохо.

На практике: free 'указатель означает изменение кучи. Среда выполнения C практически никогда не проверяет, исходит ли переданный указатель из кучи - это было бы дорогостоящим как по времени, так и по памяти.Объедините эти два фактоида, и вы получите «free (non-malloced-ptr) будет писать что-нибудь где-нибудь» - результатом может быть некоторые из «ваших» данных, измененные за вашей спиной, нарушение прав доступа или уничтожение жизненно важных структур времени выполнения, таких как адрес возврата в стеке.

Пример: катастрофический сценарий:
Ваша куча реализована как простой список свободных блоков. malloc означает удаление подходящего блока из списка, free означает его повторное добавление в список. (типичная, хотя и тривиальная реализация)

Вы освобождаете () указатель на локальную переменную в стеке. Вам «повезло», потому что модификация попадает в ненужное пространство стека. Однако часть стека теперь в вашем списке бесплатного.

Из-за конструкции распределителя и ваших шаблонов распределения маловероятно, что malloc вернет этот блок. Позже, в совершенно несвязанной части программы, вы действительно получаете этот блок как результат malloc, запись в него приводит к удалению некоторых локальных переменных вверх по стеку, а при возврате некоторого жизненно важного указателя содержится мусор, и ваше приложение вылетает. Симптомы, воспроизведение и местонахождение совершенно не связаны с действительной причиной.

Отладить это.

10
ответ дан 4 December 2019 в 06:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: