Безопасно ли использовать realloc? - PullRequest
13 голосов
/ 31 января 2012

Некоторое время назад мой друг сказал мне не использовать realloc, потому что это небезопасно, но он не мог сказать мне, почему, поэтому я провел небольшое исследование по этому вопросу, и ближайшие ссылки на мои сомнения были:
https://buildsecurityin.us -cert.gov / bsi / статьи / знания / кодирование / 809-BSI.html
http://www.iso -9899.info / wiki / Why_not_realloc
IХотите узнать, могу ли я продолжать использовать realloc в своем коде или это небезопасно, есть ли другой способ перераспределения памяти?Спасибо за ваше внимание.

Ответы [ 4 ]

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

Это совершенно безопасно для использования realloc.Это способ перераспределения памяти в программе на Си.

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

p = realloc(p, new_size); // don't do this!

Если это не удастся, realloc возвращает NULL и вы потеряли доступ к p.Вместо этого сделайте это:

new_p = realloc(p, new_size);
if (new_p == NULL)
    ...handle error
p = new_p;
14 голосов
/ 31 января 2012

Первая из двух связанных статей поднимает две жалобы выше и выходит за рамки уже поднятых здесь пунктов «проверьте вызов успешно».

Когда это сделано, старое содержимое отбрасывается и где-то остается в памяти. Для приложений с защищенной памятью, где важно стереть все следы данных, такое поведение не подходит.

Это допустимая точка , если вы храните конфиденциальные данные (например, закрытые ключи, не хэшированные (!) Пароли и т. Д.) И хотите, чтобы эксплойты затруднили восстановление данных или других процессов в системе, чтобы украсть данные.

Поскольку он перемещает память, любые старые указатели на эту память становятся недействительными и могут привести к сбою программы или неправильному поведению.

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

Если вы играете на realloc(), не двигаясь, а постоянно растете, у вас, вероятно, возникнут большие проблемы, и переключение на malloc() + copy + free() не может решить эту проблему.


Помимо пункта «проверьте правильность возвращаемого значения» наиболее интересным моментом из второй статьи является предупреждение о:

Не перераспределяйте буфер по 1 байту за раз.

они предупреждают:

Это гарантированно изменит вашу кучу памяти

Это потенциально верный момент, но это не критика самого realloc(); то же самое произошло бы, если бы вы использовали malloc() + copy + free(). Реальное исправление состоит в том, чтобы разумно наращивать буферы независимо от того, как вы их увеличиваете или, что еще лучше, распределять их по размерам в правильных размерах.

У них также есть пункт о

Использование realloc для возврата памяти в систему.

Они верны здесь в том, что использование любого размера, кроме 0, может на самом деле не возвращать. Это, вероятно, не делает вещи хуже, но это использование все еще кажется примером преждевременной «оптимизации». И снова исправление заключается в использовании разумных размеров для начала.

Сортировать ответ: это небезопасно, но это не волшебное решение всех ваших проблем.

6 голосов
/ 31 января 2012

realloc сам по себе безопасен, но использовать его безопасно немного сложно - до такой степени, что я бы сказал, что примерно 85-90% кода, который я видел, использует его не делай так безопасно.Проблема в том, что realloc возвращает NULL, чтобы указать на сбой - но когда это происходит, указатель, который вы указали в качестве ввода, все еще действителен (при условии, что вы не изменили его распределение на 0).

Следовательно,Вы должны назначить возврат из realloc указателю, который вы указали в качестве ввода, если и только если realloc вернул ненулевой указатель.Если он возвращает нулевой указатель, ваш предыдущий указатель действителен, но распределение не было изменено.

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

0 голосов
/ 31 января 2012

Как и все в Си, пока ты знаешь, что делаешь, все нормально.

(Знание того, что вы делаете, включает проверку на ошибки, не используйте старый указатель и т. Д.)

...