LINUX.ORG.RU

Как вызвать exec* без утечки памяти?

 ,


1

1

Когда вызывается функция семейства exec, то параметры копируются в память нового процесса, который замещает текущий без возможности возврата.

Соответственно, если параметры выделены на куче - формально происходит утечка памяти (still reachable в формулировке valgrind). Да, система заберет память назад по завершению процесса (флаг on close). Но ведь формально это неправильно.

Речь про случай, когда мы делаем fork перед exec.

Если выделять на стеке - то тогда есть жесткое ограничение на размер аргументов (плюс стек не резиновый, команда формально может быть до 3.5 Гб длиной, а стек всего метр-4).

Или может можно как-то по другому выделить?

★★★

Когда вызывается функция семейства exec, то параметры копируются в память нового процесса, который замещает текущий без возможности возврата.

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

?????

anonymous ()

Когда ты делаешь exec, процесс замещается новым. Целиком, со всеми потрохами (т. е. адресным пространством). Вся память, выделенная в этом процессе ранее, освобождается.

intelfx ★★★★★ ()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

Вся память, выделенная в этом процессе ранее, освобождается.

Но не программистом, а системой. Соответственно все счетчики памяти, пользовательские или valgrind’овские считают что это lost.

PPP328 ★★★ ()
Ответ на: комментарий от anonymous
switch(fork()) {
    case -1 : exit(1);
    case 0 :
       char ** args = allocate_args(...);
       execl(args[0], args);
       // never reached if started;
    default:
       ...
}

Формально, ресурс аллоцирован программистом, но не был освобожден им. Если проект использует кастомный аллокатор с подсчетом памяти либо valgrind (что тоже самое), то он заявит об утечке.

PPP328 ★★★ ()

У тебя есть форк, который создает новый процесс с той же таблицой страниц. Дальше ты вызываешь exec*, который сначала проверяет останется ли у тебя 3/4 на стеке для запуска бинарника и подсчитывает количество аргументов. Если все ок, то exec копирует параметры себе в структуру(binprm или как-то так называется, лень искать), ну и дальше уже в свою vma начинает копировать бинарник с последующим началом исполнения. Команды на 3.5Гб быть не может, длинна пути файла тоже лимитирована, аргументы окружения тоже лимитированы. После удачного запуска можешь почистить аргументы в родительском процессе, если выделил их в хипе.

xpahos ★★★★★ ()
Последнее исправление: xpahos (всего исправлений: 1)
Ответ на: комментарий от xpahos

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

Во. А если память была выделена в родительском процессе до форка - форк не создаст ее копию когда я к ней обращусь при использовании в качестве аргуметов в exec?

PPP328 ★★★ ()

команда формально может быть до 3.5 Гб длиной, а стек всего метр-4

Так аргументы команды же на стек в итоге и складываются, лул.

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

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

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

это правильно

тупняк какой-то

с точки зрения … анализа

с моей точки зрения твои анализаторы говно, тк не учитывают, что exit() всё чистит. кто знает, какими ещё false positive они тебя дурят

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

Я в вашем примере, после комментария:

// never reached if started;

не увидил вызова exit(). Вот мне и стало интерестно. Сначала я подумал, что вы не делете exit() после exec(). А теперь, боюсь подумать, что вы между exec() и exit() в потомке суёте кучу free(), чтобы операционке, которая и так по каким-то причинам не смогла exec() стало ещё веселее от выделения памяти под CoW из-за free().

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

не увидил вызова exit()

Потому что точки после exec программа в случае успеха в exec не достигнет. Процесс будет заморожен, смапится в память бинарь указанный в exec, и всё, возврата обратно не будет, процесс замещен.

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

Формально, ресурс аллоцирован программистом, но не был освобожден им.

Формально ресурс был освобождён успешным вызовом execl. Баги анализаторов posix не колышут.

anonymous ()