V623. Consider inspecting the '?:' operator. A temporary object is being created and subsequently destroyed.


Анализатор обнаружил возможную ошибку при работе с тернарным оператором '?:'. Если при работе с оператором '?:' совместно используются объект типа класс и любой другой тип, который может быть преобразован к данному классу, то создаются временные объекты. Временные объекты будут удалены по завершению оператора '?:'. Ошибка возникает, если мы при этом сохраняем результат в переменную типа указатель. Рассмотрим пример:

CString s1(L"1");
wchar_t s2[] = L"2";
bool a = false;
...
const wchar_t *s = a ? s1 : s2;

В результате выполнения этого кода переменная 's' будет указывать на данные, находящиеся внутри временного объекта. Беда в том, что этот объект уже уничтожен!

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

wchar_t s1[] = L"1";
wchar_t s2[] = L"2";
bool a = false;
...
const wchar_t *s = a ? s1 : s2;

Другой вариант корректного кода:

CString s1(L"1");
wchar_t s2[] = L"2";
bool a = false;
...
CString s = a ? s1 : s2;

Предупреждение V623 требует со стороны программиста повышенного внимания. Беда в том, что ошибки данного типа хорошо прячутся. Код, содержащий подобные ошибки может успешно работать многие годы. Но это только иллюзия, что он работает. На самом деле используется освобождённая память. То, что в памяти находятся корректные данные - это только везение. Поведение программы может поменяться в любой момент. Это может произойти при смене версии компилятора. Это может произойти, после рефакторинга кода, когда появляется новый объект, использующий ту же область памяти. Рассмотрим это на примере.

Напишем, скомпилируем и запустим следующий код:

bool b = false;
CComBSTR A("ABCD");
wchar_t *ptr = b ? A : L"Test OK";
wcout << ptr << endl;

Этот код мы скомпилировали с помощью Visual Studio 2010 и он распечатал "Test OK". Может показаться, что всё работает правильно. Но внесём в код небольшую правку:

bool b = false;
CComBSTR A("ABCD");
wchar_t *ptr = b ? A : L"Test OK";
wchar_t *tmp = b ? A : L"Error!";
wcout << ptr << endl;

Кажется строчка, где инициализируется переменная 'tmp' ничего не изменит. Но это не так. Теперь программа печатает на экран: "Error!".

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

Согласно Common Weakness Enumeration, потенциальные ошибки, найденные с помощью этой диагностики, классифицируются как CWE-416.

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


Найденные ошибки

Проверено проектов
354
Собрано ошибок
13 290

А ты совершаешь ошибки в коде?

Проверь с помощью
PVS-Studio

Статический анализ
кода для C, C++, C#
и Java

goto PVS-Studio;