Как статически определить динамическое выделение кучи? - PullRequest
0 голосов
/ 16 октября 2018

Я собираюсь удалить «как можно больше» динамического распределения кучи в моем приложении, и мне интересно, как я могу убедиться, что ничего не пропустил.

В настоящее время я ищу способлегко или даже автоматически определить, могут ли какие-либо (или какие) части кода вызывать стандартные реализации new / delete или malloc / free без необходимости динамического отслеживания выделений (т. е. с помощью статического анализа кода)или обратная связь от компилятора / компоновщика).

Легко обнаружить (или найти) код, который напрямую вызывает new или malloc, конечно:

int main() {
  auto s = new std::string();
  delete s;
}

На всякий случайвыделения скрыты глубоко в сторонней библиотеке или в случаях, которые менее очевидны (например, throw), я все еще могу искать искаженные символы для нового / удаления в моем двоичном файле:

g++ main.cpp
nm a.out | grep -E "_Znwm|_Znam|_Znwj|_Znaj|_ZdlPv|_ZdaPv|malloc|free"
                 U _ZdlPvm@@CXXABI_1.3.9
                 U _Znwm@@GLIBCXX_3.4

Но этот подходбудет только прямой использования new/delete/malloc/free.В случае, если мой код (или материал сторонних производителей) использует стандартную библиотеку, вы не обнаружите ее, просто позвонив по номеру nm:

int main() {
    std::string a;
    for(int i = 0; i < 100; ++i) {
        a += "data ";
    }
}

Мой текущий подход заключается в связывании со статическими стандартными библиотеками (-static-libgcc / -static-libstdc++) и посмотрите, есть ли ссылка на new / delete на всех во всем двоичном файле:

g++ -static-libgcc -static-libstdc++ main.cpp
nm a.out | grep -E "_Znwm|_Znam|_Znwj|_Znaj|_ZdlPv|_ZdaPv|malloc|free"
0000000000471fd0 T __cxa_free_dependent_exception
0000000000471f30 T __cxa_free_exception
                 U free@@GLIBC_2.2.5
                 U __freelocale@@GLIBC_2.2.5
                 U malloc@@GLIBC_2.2.5
0000000000471b20 T _ZdlPv
0000000000491bf0 T _ZdlPvm
0000000000471bc0 t _ZN12_GLOBAL__N_14pool4freeEPv.constprop.2
0000000000402a20 t _ZN12_GLOBAL__N_14pool4freeEPv.constprop.2.cold.5
0000000000471e80 T _ZN9__gnu_cxx9__freeresEv
0000000000472240 T _Znwm
0000000000491c00 T _ZnwmRKSt9nothrow_t
0000000000403f37 t _ZnwmRKSt9nothrow_t.cold.0

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

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

Каковы ваши подходы, инструменты, опыт?

1 Ответ

0 голосов
/ 17 октября 2018

Одной из стратегий может быть обернуть вызовы malloc / calloc вашей собственной функцией, которая решает, разрешены ли они, и утверждает (или регистрирует), если нет.Решение может быть принято путем проверки глобального флага, который вы установили / сбросили во время инициализации, обработчиков ошибок и т. Д.

Это, конечно, не статично, но это может послужить хорошей отправной точкой для очистки вашегокод.

...