# V586. The 'Foo' function is called twice to deallocate the same resource.

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

Ресурсом может быть память, файл или, например, объект HBRUSH.

Рассмотрим пример некорректного кода:

    float *p1 = (float *)malloc(N * sizeof(float));
    float *p2 = (float *)malloc(K * sizeof(float));
    ...
    free(p1);
    free(p1);

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

Более того, подобный код является дефектом безопасности и может привести к возникновению уязвимости. Например, уязвимости подвержена функция 'malloc' ('dmalloc') Дуга Ли (Doug Lea), которая используется в некоторых библиотеках как 'malloc' по умолчанию. Для возникновения уязвимости, связанной с двойным освобождением памяти, требуется несколько условий: блоки памяти, смежные с освобождаемым, не должны быть свободны, а список свободных блоков памяти должен быть пуст. В этом случае возможно создание эксплойта. Несмотря на то что подобные уязвимости сложно использовать из-за необходимости специфичной конфигурации памяти, существуют реальные примеры уязвимого кода, который был успешно взломан.

Корректный вариант:

    float *p1 = (float *)malloc(N * sizeof(float));
    float *p2 = (float *)malloc(K * sizeof(float));
    ...
    free(p1);
    free(p2);

Иногда ошибка двойного освобождения ресурсов не является опасной:

    vector<unsigned> m_arrStack;
    ...
    m_arrStack.clear();
    m_arrBlock.clear();
    m_arrStack.clear();

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

Корректный вариант:

    vector<unsigned> m_arrStack;
    ...
    m_arrStack.clear();
    m_arrBlock.clear();

Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки управления динамической памятью (выделения, освобождения, использования освобожденной памяти) [* см. примечание касательно языков C#, Java].

Данная диагностика классифицируется как:

CWE-415 CWE-675 CERT-MEM30-C CERT-MEM50-CPP

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