Sunday, December 2, 2012

Ловим убежавшие байты рыболовной сетью

В ходе работы над движком появилась нужда в тулзе, что приглядывает за выделенными, но не освобождённой памятью. После некоторых дискуссий с моим коллегой Вадимом (Vadzim Struk) и поисках в интернетах было принято решение действовать, и был утверждён план.

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

В качестве инструментов разработки хотелось воспользоваться GNU autotools, но они не были осилены во время и показались слишком громоздкими. Выбор пал на самописные makefile, писал которые я в emacs. В ходе разработки понадобился gdb (куда же без него) и в качестве эталона valgrind, им я проверял свою библиотеку на наличие утечек. Обычный emacs так же стал инструментом разработки, до сих пор на него не нарадуюсь. Правда можно сделать его чуть удобнее с помощью cedet и ecb, но их я пока не осилил. Обязательно попробую :)

Началось всё с определения метода перегрузки функций выделения памяти. В начале совершенно случайно я наткнулся на отличную статью посвящённую как раз рассматриваемой проблеме (link). Там подглядел решение в стиле переопределение функции макрсом. Не самое лучшее решение, ибо код придётся перекомпилировать каждый раз, когда подключается моё решение, но у меня не было желания писать свой valgrind.

Кстати функций выделения памяти оказалось чуть больше, чем я предполагал по началу. Списочек: new, new[], malloc, calloc, realloc. И действия некоторых из них оказались совсем не очевидными. Эх, какой же хитрый этот realloc. Реализует сразу 3 модели поведения. Но не будет вдаваться в нюансы реализации функций C. Ибо цель-то не в ней.

Был написан define всех функций. В переопределяющих функциях вызывался обычный cout с выводом в стиле:
ptr 0x0a43d452 created in main.cpp:13
Код ушёл в репозиторий. На форуме GameDev.net появилась тема посвящённая моему труду с целью сбора фидбеков (кстати как раз там мне и указали на calloc и realloc).

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

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