Неверно положительный V595 Указатель ‘_parent’ использовался до того, как был проверен на nullptr

Я использую PVS-Studio для своего проекта Torrent File Editor. Есть один ложный положительный результат. Вот нет реальной проблемы, но я получаю такую ​​ошибку:

torrent-file-editor/abstracttreenode.h:138: error: V595 The '_parent' pointer was utilized before it was verified against nullptr. Check lines: 138, 139.

Фрагмент кода:

inline T *sibling(int row) const
{
Q_ASSERT(_parent);
Q_ASSERT(row < _parent->childCount()); // -V595 PVS-Studio
return _parent ? _parent->child(row) : nullptr;
}

Здесь Q_ASSERT — только проверка отладочной версии. Такая проверка не выполняется в версии Release. Для выпуска я использую _parent ? ... : ... чтобы предотвратить возможный сбой. Так что все в порядке, что проверка дублируется в версии отладки.

Я подавляю этот ложный позитив специальным комментарием. Так что это не проблема, но подумайте, что PVS-Studio должна справиться с этим делом.

0

Решение

V595 Диагностическая логика проста. Предупреждение выдается в том случае, если в начале разыменовывается указатель, а затем проверяется равенство nullptr.

Конечно, есть ряд ситуаций, когда анализатор будет тихо, встретив такой паттерн. Включая ситуацию, когда указатель не равен nullptr, поэтому анализатор будет молчать.

Тем не менее Q_ASSERT(_parent) не гарантирует, что указатель _parent ненулевой Если _parent ноль, Q_ASSERT оператор выведет следующее сообщение, используя qFatal функция. Если вы используете обработчик сообщений по умолчанию, эта функция прервет создание дампа памяти.

Вы можете установить свой собственный обработчик, который продолжит запуск программы. Так что теоретически анализатор прав. Возможна разыменование нулевого указателя.

Мы не теоретики, а практики, и мы понимаем, что этот кодекс следует считать правильным. Анализатор не знаком с таким представлением кода, где макрос Q_ASSERT используется еще. Мы изменим анализатор, чтобы он начал воспринимать такие шаблоны кода как правильные. То есть в будущем анализатор будет предполагать, что здесь:

Q_ASSERT(_parent);
Q_ASSERT(row < _parent->childCount());

_parent->childCount() вызов функции никогда не выполняется, если указатель _parent равно nullptr. Если указатель равен нулю, то программа перестанет работать раньше из-за вызова qFatal(),

Конечно, как я уже сказал выше, вы можете изменить поведение обработчика, и это не приведет к прерыванию работы программы. Однако на практике никто не изменит обработчик и не напишет такой код, который мы здесь рассматриваем.

Это может быть конечной точкой ответа. Итак, мы улучшим анализатор и все. Однако невозможно предусмотреть все возможные варианты. Как подавить предупреждение, если это наш собственный макрос?

Предположим, что эта самодельная система регистрации ошибок и анализатор ничего не знают о пользовательских функциях Foo(),

void Foo(bool expr);
#define Q_ASSERT(expr) Foo(expr);

inline T *sibling(int row) const
{
Q_ASSERT(_parent);
Q_ASSERT(row < _parent->childCount())
return _parent ? _parent->child(row) : nullptr;
}

Самый простой, но не самый лучший способ — явно пометить предупреждение как ложное, используя комментарии:

Q_ASSERT(row < _parent->childCount())   //-V595

Другой вариант — изменить стиль написания кода и писать следующим образом:

inline T *sibling(int row) const
{
if (_parent == nullptr)
{
Q_ASSERT(false);
return nullptr;
}
Q_ASSERT(row < _parent->childCount());
return _parent->child(row);
}

Для такого кода анализатор не выдаст предупреждение V595, так как для этого нет причин. Код стал немного длиннее, но, на мой взгляд, теперь он более логически корректен и безопасен. Я рекомендую этот способ борьбы с этим типом предупреждений.

И последнее — использовать механизм подавления предупреждений в макросах. Для этого в заголовочном файле, где определен макрос, вы должны написать комментарий:

//-V:Q_ASSERT:595

После этого предупреждения исчезнут. Конечно, не всегда возможно изменить файл, в котором объявлен макрос. Затем вы можете использовать один из глобальных файлов. В проектах Visual C ++ хорошим кандидатом является stdafx.h. Другой вариант — использовать файлы конфигурации диагностики (pvsconfig). Все эти методы подробно описаны в документации в разделе «Подавление ложных срабатываний«. база разметки также существует.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]