Как регистрировать malloc

Это немного гипотетично и сильно упрощено, но...

Предположим, что программа будет вызывать функции, написанные третьими лицами. Эти стороны можно считать невраждебными, но нельзя считать их «компетентными». Каждая функция будет принимать некоторые аргументы, иметь побочные эффекты и возвращать значение. У них нет состояния, пока они не запущены.

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

Это возможно? Это практично?

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


person BCS    schedule 08.09.2008    source источник


Ответы (11)


Вы не указываете операционную систему или среду, этот ответ предполагает Linux, glibc и C.

Вы можете установить __malloc_hook, __free_hook и __realloc_hook, чтобы они указывали на функции, которые будут вызываться из malloc(), realloc() и free() соответственно. Существует справочная страница __malloc_hook, показывающая прототипы. Вы можете добавить отслеживание распределения в эти хуки, а затем вернуться, чтобы позволить glibc обрабатывать выделение/освобождение памяти.

Похоже, вы хотите освободить любые активные распределения, когда сторонняя функция вернется. Есть способы, чтобы gcc автоматически вставлял вызовы при каждом входе и выходе из функции, используя -finstrument-functions, но я думаю, что это было бы неэлегантно для того, что вы пытаетесь сделать. Можете ли вы, чтобы ваш собственный код вызывал функцию в вашей библиотеке отслеживания памяти после вызова одной из этих сторонних функций? Затем вы можете проверить, есть ли какие-либо выделения, которые сторонняя функция еще не освободила.

person DGentry    schedule 08.09.2008

Во-первых, вы должны предоставить точки входа для malloc() и free() и друзей. Поскольку этот код уже скомпилирован (правильно?), вы не можете полагаться на #define для перенаправления.

Затем вы можете реализовать их очевидным образом и зарегистрировать, что они пришли из определенного модуля, связав эти подпрограммы с этими модулями.

Самый быстрый способ предполагает отсутствие ведения журнала вообще. Если объем используемой ими памяти ограничен, почему бы не заранее выделить всю «кучу», которая им когда-либо понадобится, и не написать на ее основе распределитель? Затем, когда это будет сделано, освободите всю «кучу», и все готово! Вы можете распространить эту идею на несколько куч, если она более сложная.

Если вам действительно нужно «логировать», а не создавать собственный распределитель, вот несколько идей. Во-первых, используйте хеш-таблицу с указателями и внутренней цепочкой. Другим вариантом было бы выделить дополнительное пространство перед каждым блоком и поместить туда свою собственную структуру, содержащую, скажем, индекс в вашей «таблице журнала», а затем сохранить свободный список записей таблицы журнала (в виде стека, поэтому получение бесплатного или возвращение бесплатного - O (1)). Это требует больше памяти, но должно быть быстрым.

Это практично? Я думаю, что да, пока скорость удара приемлема.

person Jason Cohen    schedule 08.09.2008

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

person user4891    schedule 08.09.2008

Лучшее решение, чем попытка протоколировать malloc, может состоять в том, чтобы помещать функции в песочницу при их вызове — предоставлять им доступ к фиксированному сегменту памяти, а затем освобождать этот сегмент, когда функция завершает работу.

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

person Yes - that Jake.    schedule 08.09.2008

Разве вы не можете просто заставить их выделить всю свою память в стеке? Таким образом, будет гарантировано освобождение после выхода из функции.

person Mo.    schedule 08.09.2008

В прошлом я написал программную библиотеку на C, в которой была подсистема управления памятью, позволяющая регистрировать выделение и освобождение памяти, а также вручную сопоставлять каждое выделение и освобождение. Это было полезно при поиске утечек памяти, но это было сложно и отнимало много времени. Количество журналов было огромным, и потребовалось много времени, чтобы понять журналы.

При этом, если ваша сторонняя библиотека имеет обширные распределения, скорее всего, нецелесообразно отслеживать это с помощью ведения журнала. Если вы работаете в среде Windows, я бы посоветовал использовать такие инструменты, как Purify[1] или BoundsChecker[2], которые должны обнаруживать утечки в ваших сторонних библиотеках. Инвестиции в инструмент должны окупиться за сэкономленное время.

[1]: http://www-01.ibm.com/software/awdtools/purify/ Очистить

[2]: http://www.compuware.com/products/devpartner/visualc.htm Проверка границ

person Steve Wranovsky    schedule 08.09.2008

Поскольку вы беспокоитесь об утечках памяти и говорите о malloc/free, я предполагаю, что вы находитесь в C. Я также предполагаю, исходя из вашего вопроса, что у вас нет доступа к исходному коду сторонней библиотеки.

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

person 17 of 26    schedule 08.09.2008

Если у вас есть лишние деньги, рассмотрите возможность использования Purify для отслеживания проблем. Он творит чудеса и не требует исходного кода или перекомпиляции. Существуют также другие библиотеки отладки malloc, которые дешевле. Electric Fence — это одно имя, которое я помню. Тем не менее, хуки отладки, упомянутые Дентоном Джентри, тоже кажутся интересными.

person Jonathan Leffler    schedule 21.10.2008

Если вы слишком бедны для Purify, попробуйте Valgrind. Это намного лучше, чем 6 лет назад, и в него намного легче погрузиться, чем в Purify.

person Mitch Haile    schedule 21.10.2008
comment
Да, valgrind тоже неплохо работает. Спасибо за напоминание. - person Jonathan Leffler; 21.10.2008

Microsoft Windows предоставляет (используйте SUA, если вам нужен POSIX), вполне возможно, самую продвинутую инфраструктуру кучи + (другие API, которые, как известно, используют кучу) из любой поставляемой ОС сегодня.

ловушки отладки __malloc() и связанные с ними интерфейсы отладки CRT хороши для случаев, когда у вас есть исходный код для тестов, однако они часто могут пропустить выделения стандартными библиотеками или другим связанным кодом. Это ожидаемо, поскольку они представляют собой инфраструктуру отладки кучи Visual Studio.

gflags очень полный и подробный набор возможностей отладки, который был включен в Windows на протяжении многих лет. Наличие расширенной функциональности только для исходных и двоичных вариантов использования (поскольку это инфраструктура отладки кучи ОС).

Он может регистрировать полные трассировки стека (репагинация символической информации в операции постобработки) всех пользователей кучи, для всех точек входа, изменяющих кучи, последовательно, если это необходимо. Кроме того, он может изменить кучу с патологическими случаями, которые могут выровнять распределение данных таким образом, чтобы защита страницы, предлагаемая системой VM, была назначена оптимально (т. е. выделить запрошенный блок кучи в конце страницы, так что даже переполнение одного байта обнаруживается в момент переполнения.

umdh — это инструмент, который может помочь оценить состояние на различных контрольных точках, однако данные постоянно накапливаются во время выполнения цели. o Это не простая отладочная остановка контрольной точки в традиционном контексте. Кроме того, ВНИМАНИЕ, последний раз, когда я проверял, по крайней мере, общий размер кольцевого буфера, в котором хранится информация о стеке, для каждого запроса несколько мал (64 тыс. записей (записи + стек)), поэтому вам может понадобиться для быстрого создания дампа для пользователей с тяжелой кучей. Есть и другие способы доступа к этим данным, но umdh довольно прост.

ПРИМЕЧАНИЕ существует 2 режима;

  1. РЕЖИМ 1, umdh {-p:идентификатор_процесса|-pn:имя_процесса} [-f:имя_файла] [-g]
  2. РЕЖИМ 2, umdh [-d] {Файл1} [Файл2] [-f:ИмяФайла]

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

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

Выполнение gflags без аргументов для режима пользовательского интерфейса, +arg и /args также являются различными «режимами» использования.

person RandomNickName42    schedule 02.06.2009

В Linux я успешно использовал mtrace(3) для регистрации выделений и освобождение. Его использование так же просто, как

  1. Измените свою программу, чтобы она вызывала mtrace(), когда вам нужно начать трассировку (например, в начале main()),
  2. Задайте для переменной среды MALLOC_TRACE путь к файлу, в котором должна быть сохранена трассировка, и запустите программу.

После этого выходной файл будет содержать что-то вроде этого (отрывок из середины, показывающий неудачное выделение):

@ /usr/lib/tls/libnvidia-tls.so.390.116:[0xf44b795c] + 0x99e5e20 0x49
@ /opt/gcc-7/lib/libstdc++.so.6:(_ZdlPv+0x18)[0xf6a80f78] - 0x99beba0
@ /usr/lib/tls/libnvidia-tls.so.390.116:[0xf44b795c] + 0x9a23ec0 0x10
@ /opt/gcc-7/lib/libstdc++.so.6:(_ZdlPv+0x18)[0xf6a80f78] - 0x9a23ec0
@ /opt/Xorg/lib/video-libs/libGL.so.1:[0xf668ee49] + 0x99c67c0 0x8
@ /opt/Xorg/lib/video-libs/libGL.so.1:[0xf668f14f] - 0x99c67c0
@ /opt/Xorg/lib/video-libs/libGL.so.1:[0xf668ee49] + (nil) 0x30000000
@ /lib/libc.so.6:[0xf677f8eb] + 0x99c21f0 0x158
@ /lib/libc.so.6:(_IO_file_doallocate+0x91)[0xf677ee61] + 0xbfb00480 0x400
@ /lib/libc.so.6:(_IO_setb+0x59)[0xf678d7f9] - 0xbfb00480
person Ruslan    schedule 16.02.2020