LINUX.ORG.RU

Правильное использование realloc

 ,


0

5

Статические анализаторы любят ругаться на такую конструкцию:

ptr=realloc(ptr, size);

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

★★

то значит, все очень плохо и программе нет смысла работать.

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

Harald ★★★★★ ()
Ответ на: комментарий от dt1

Например, это может быть какой-нибудь буфер или кэш, ускоряющий работу.

Harald ★★★★★ ()

то значит, все очень плохо и программе нет смысла работать.

А когда у программы зарегистрированы 100500 соединений, и только вот на следующее не хватило памяти?

gag ★★★★★ ()

Если память не выделилась, то значит,

Что что-то пошло не так. Например, при вычислении size было численное переполнение или иным образом возникло отрицательное число (очень большое беззнаковое), которое и приводит к ошибке, а памяти на самом деле ещё много.

все очень плохо и программе нет смысла работать.

Но может иметь смысл завершиться корректно: освободить, что можно, сохранить пользовательские данные и выйти. Либо ничего не делать. Зажравшийся процесс будет убит и тогда можно продолжать работать. Если бы все программы игнорировали нехватку памяти, то при OOM система бы тупо гасла, без возможности что-либо сделать (как пример, я видел у bash ошибку «нет памяти», за N попыток во время работы случайной fork-бомбы удалось выполнить mv /bin/bash{,_} и восстановить работоспособность системы).

xaizek ★★★★★ ()

то значит, все очень плохо и программе нет смысла работать

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

anonymous ()

Ну и что? Если память не выделилась, то значит, все очень плохо и программе нет смысла работать

Тебе нет смысла работать на работе, связанной с компьютерами и вообще техникой. Но не переживай, третий заместитель второго помощника младшего дворника — тоже профессия.

redgremlin ★★★★★ ()

в ptr запишется 0

Не 0, а NULL:

https://kristerw.blogspot.ru/2016/03/pointer-casts-in-c.html

https://kristerw.blogspot.ru/2016/08/surprising-properties-of-c-null-pointer....

Она грохнется при попытке разыменовать ptr.

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

Во-вторых, что будет, если программа попытается записать что-нибудь не в ptr, а сразу в ptr+offset, где сам offset имеет смысл как указатель?

doushiyou ()
Ответ на: комментарий от doushiyou

Ну и сообщение “Out of memory” всяко лучше, чем “Segmentation fault”.

doushiyou ()
Ответ на: комментарий от xaizek

Но может иметь смысл завершиться корректно: освободить, что можно, сохранить пользовательские данные и выйти.

это может быть нетривиально, не факт ведь, что при сохранении не потребуется выделить память

dt1 ★★ ()
Ответ на: комментарий от anonymous

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

Куда написать? Если это графическая прога, то 99%, что вывод сообщения потребует выделения памяти, а ее нет.

dt1 ★★ ()

В таком выражении, если realloc вернёт NULL, то кусок памяти, на который указывал ptr до вызова, никто не освободит. Утечка памяти-с.

uuwaan ★★ ()
Ответ на: комментарий от uuwaan

кусок памяти, на который указывал ptr до вызова, никто не освободит

ОС освободит, когда прога грохнется.

dt1 ★★ ()
Ответ на: комментарий от dt1

Её только на открытие документа нет же.

Но к линуксу все эти рассуждения относятся слабо, ибо overcommit по умолчанию.

doushiyou ()
Ответ на: комментарий от dt1

Ты упомянул, что статический анализатор ругается. Я тебе объясняю почему. Анализатору высокие материи по барабану. Он знать не знает, что ты процесс ронять собрался при ошибке выделения памяти.

uuwaan ★★ ()

Если память не выделится, то в ptr запишется 0, а старое значение ptr будет потеряно, ужас-ужас.

Верно, произойдёт утечка памяти.

Ну и что? Если память не выделилась, то значит, все очень плохо и программе нет смысла работать.

Может так, а может и не так. Никто не мешает писать программу, которая будет работать в условиях недостатка памяти.

Она грохнется при попытке разыменовать ptr.

ptr можно сравнить с NULL-ом перед разыменованием.

Legioner ★★★★★ ()
Ответ на: комментарий от dt1

«Нет памяти» понятие растяжимое. Если ты хотел 10 байт, а тебе показали дулю, то да, всё плохо и можно тушить свет. Однако для большого размера просто может не найтись непрерывного куска памяти нужной длины, и в такой ситуации можно выделять память меньшими порциями под задачи обработки ошибки.

uuwaan ★★ ()
Ответ на: комментарий от dt1

это может быть нетривиально, не факт ведь, что при сохранении не потребуется выделить память

Многие критические программы пишут вообще без использования динамически выделяемой памяти.

Legioner ★★★★★ ()
Ответ на: комментарий от dt1

Программа раобтает так как она написана, а не так как хотел программист!

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

PS. А раз в API не предусмотрено такого использования, то все, что потом произойдет - это ужа на твоей совести, включая коллапс в виде kernel panik.

PPS. Т.е. ты можешь использовать так, как написал, но под свою ответственность.

Vic ()
Ответ на: комментарий от dt1

это может быть нетривиально, не факт ведь, что при сохранении не потребуется выделить память

Для этого код сохранения пишется без выделения памяти либо с выделением её на старте приложения.

xaizek ★★★★★ ()
Ответ на: комментарий от dt1

Куда написать? Если это графическая прога, то 99%, что вывод сообщения потребует выделения памяти, а ее нет.

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

anonymous ()
Ответ на: комментарий от anonymous

Ну и не стоит забывать, что при откате задачи все что было на нее выделено - вернется.

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

dt1 ★★ ()
Ответ на: комментарий от dt1

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

И желательно на стеке (локальные переменные функций), а не в куче.

Vic ()
ptr=realloc(ptr, size);
if (!ptr)
  abort();
anonymous ()

Если память не выделилась, то значит, все очень плохо и программе нет смысла работать.

Ну-ну.

Deleted ()

Кстати, в Linux-е зачастую проблема другая, если памяти нет, то realloc()-то тебе память «выделит» и новый ptr будет не NULL, а попытаешься поработать с ptr в новой области, программа рухнет по нехватке памяти.

https://linux.die.net/man/3/malloc

By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available.

Vic ()

Освободить память, сохранить текущие результаты, сказать пользователю что «бида» уже не надо?

evilface ★★ ()
Ответ на: комментарий от anonymous

Это же жесть, разве нет?

Ага, особенно когда программа падает в момент финальной сдачи заказчику :-)

Vic ()
Ответ на: комментарий от quest

такие как ты и пишут systemd и pulseaudio

и ядро заодно, выше же написали: «when malloc() returns non-NULL there is no guarantee that the memory really is available»
вот ты такой умный и правильный, «грамотно» обрабатываешь нехватку памяти, сохраняешься, выдаешь пользователю сообщения, а ядро просто убивает прогу SIGKILL'ом, бггг

dt1 ★★ ()
Ответ на: комментарий от invy

не использовать realloc

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

dt1 ★★ ()
Ответ на: комментарий от Vic

И желательно на стеке (локальные переменные функций), а не в куче.

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

dt1 ★★ ()
Ответ на: комментарий от dt1

Какое тебе дело до внутренностей либ? Зачем ты на них натравляешь статический анализатор?

invy ★★★★★ ()
Ответ на: комментарий от dt1

... вот ты такой умный и правильный, «грамотно» обрабатываешь нехватку памяти, сохраняешься, выдаешь пользователю сообщения, а ядро просто убивает прогу SIGKILL'ом, бггг

Это всё зависит от настроек аллокатора и среды выполнения. Всегда можно ограничить память так, чтобы OOM срабатывал достаточно редко или вообще не работал. malloc() возвращает NULL не только когда памяти в самом деле нет, но и при достижении различных лимитов.

mashina ★★★★★ ()

правильно сохранить старый указатель в переменную. Тогда в случае возвращения 0 можно будет выдать ошибку и освободить старый указатель. Или же взять реаллок поменьше

mittorn ★★★★★ ()
Ответ на: комментарий от dt1

И желательно на стеке (локальные переменные функций), а не в куче.

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

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

У меня встречный вопрос, а что тебя заставило прошерстить свой/не свой код статическим анализатором?

Vic ()

не знаю писал ли кто-то, но если будет Nptr=realloc(ptr, size); и при неудачи, можно дальше работать с ptr, т.к. realloc его трогать не будет.

SmilePlz ()
Ответ на: комментарий от mashina

Всегда можно ограничить память так, чтобы OOM срабатывал достаточно редко или вообще не работал.

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

dt1 ★★ ()
Ответ на: комментарий от Deleted

существует мир за пределами Linux

да, радужный и веселый

dt1 ★★ ()
Ответ на: комментарий от Vic

Во-первых, сообщение в журнал, т.к. в консоли его ни кто не заметит.

не факт, что в него что-то запишется, если мало памяти

У тебя же достойная программа, с журналом своей работы.

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

Во-вторых, не нужно думать за X-сервер. Ему памяти может быть и достаточно.

не надо раскорячивать систему еще больше, если она и так в критическом состоянии

что тебя заставило прошерстить свой/не свой код статическим анализатором?

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

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

dt1 ★★ ()
Ответ на: комментарий от dt1

при неудачном выделении памяти проверить, сколько ее вообще осталось в системе

Норкоманство в чистом виде. При неудачном выделении памяти надо подчистить за собой уже выделенное и кинуть исключение/вернуть ошибку наверх. А там уже будут разбираться - фатально это или нет.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.