28 мар. 2013 г.

Идёт охота на жуков, идёт охота...

Так уж получилось, что мне на работе перепало счастье поддерживать древнее чудовище, выполняющее функции проксирования запросов к СУБД.
По сути это демон, который принимает запросы в виде дампа объектов, выполняет их, сериализует ответ СУБД и шлёт клиенту.
Всё это барахло написано в виде серверного приложения, клиентской библиотеки и отдельной библиотеки, содержащей описание самих сериализуемых классов (описания таблиц, столбцов, условий выборки и типов запросов).
Проблема в том, что эта хрень течёт за неделю на 10 Гигабайт.
Я решил использовать valgrind для поиска утечек. Первый раз я удивился, когда обнаружил, что на нашем девелоперском серваке нет valgrind'а. Ну ладно, поставил. Хотя странно, вроде бы уже лет 5 разработка идёт...
Второй раз я удивился, увидев результат работы valgrind. За один запрос сервер утекает на 2-3 Мегабайта. В результатах была куча текущих методов, но все они являлись просто дефолтными конструкторами передаваемых объектов.
Смутная мысль посетила меня, чтобы подтвердиться при открытии исходников: да, виртуальными деструкторами мои предшественники свой код не баловали.
Добавляю виртуальные деструкторы (это был весьма муторный процесс в виду того, что отдельная либка представляла собой хидер в овер 1500 строк без единого шаблона с объявлением и реализацией 100500 классов и файл реализации в овер 3000 строк, который тоже был способен удивить случайного зрителя тщательно припрятанными объявлениями структур и классов), чтобы обнаружить, что утечки уменьшились лишь незначительно. Всё ещё течёт некий метод getClassName.
Я вчитался в его название и на меня снизошло классическое "Ну нахера, блиать!?".
Открыв хидер, я увидел в нём следующий кусочек няшного говнокода:

#if defined(Q_OS_UNIX)
#include
#define OMAKE_CLASSNAME_METHOD\
    virtual QString getClassName() const { int status; char * realname; \
    realname = abi::__cxa_demangle(typeid(*this).name(), 0, 0, &status); \
    return QObject::tr(realname); }
#else
#define OMAKE_CLASSNAME_METHOD\
     virtual QString getClassName() const { return QObject::tr(typeid(*this).name()).remove("const").remove("class").remove("struct").remove(" ");}
#endif 

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

Там же обнаружился ещё один кандидат в палату мер и говен:

#define OMAKE_NEWINTANCE_METHOD( C )\
virtual C* newInstance(){return new C();}

Вот такие авгиевы конюшни приходится разгребать.