clang ++ 3.3 статический анализатор, как избавиться от ложного срабатывания?

Я бегал clang 3.3Статический анализатор на различных моих проектах. За исключением некоторых проблем, которые были моей собственной ошибкой (чего и следовало ожидать, я был бы очень грустным и очень самодовольным в противном случае), все прошло довольно гладко, за исключением следующей проблемы, касающейся std::functionХод конструктора, который является ложным срабатыванием.

Прежде чем обсуждать это, вот простой тестовый пример:

int main() {
std::function<void ()> f1;
std::function<void ()> f2 = std::move(f1);
}

Запустите это через clang++ -std=c++11 --analyze -Xanalyzer -analyzer-output=text foo.cpp (который использует GCC libstdc++ — а именно версия 4.8.1 — нет clang«s libc++) и вы получите следующий след:

In file included from foo.cpp:1:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/iostream:39:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ostream:38:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ios:40:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/char_traits.h:39:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_algobase.h:64:
In file included from /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/stl_pair.h:59:
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:175:7: warning: Assigned value is garbage or undefined
_Tp __tmp = _GLIBCXX_MOVE(__a);
^~~~~~~~~   ~~~~~~~~~~~~~~~~~~
foo.cpp:30:31: note: Calling move constructor for 'function'
std::function<void ()> f2 = std::move(f1);
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2232:2: note: Calling 'function::swap'
__x.swap(*this);
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:2359:2: note: Calling 'swap'
std::swap(_M_invoker, __x._M_invoker);
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:175:19: note: Calling 'move'
_Tp __tmp = _GLIBCXX_MOVE(__a);
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:142:30: note: expanded from macro '_GLIBCXX_MOVE'
#define _GLIBCXX_MOVE(__val) std::move(__val)
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:175:19: note: Returning from 'move'
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:142:30: note: expanded from macro '_GLIBCXX_MOVE'
#define _GLIBCXX_MOVE(__val) std::move(__val)
^
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/move.h:175:7: note: Assigned value is garbage or undefined
_Tp __tmp = _GLIBCXX_MOVE(__a);
^
1 warning generated.

Как видите, конструктор перемещения std::function(std::function&&) реализуется с точки зрения swap, Шаги всей операции (если верить clang):

  • f1 правильно построен
  • f2 еще не построен и, следовательно, содержит мусор
  • f1 перемещается в f2 но на самом деле это действительно swap
  • f2 теперь содержит старый f1, но f1 содержит старый f2 то есть. мусор
  • в какой-то момент, f1 содержащий мусор уничтожается … что происходит потом?

Теория говорит, что это очень плохо. На практике, глядя на реализацию, кажется, что std::function в частном порядке наследует от _Function_base который заботится о инициализации всего, что имеет значение (т.е. _M_manager) к нулю, так clangпредупреждение о _M_invoker бессмысленно.

На всякий случай, если кто-то сомневается, перемещение объекта должно оставить его в неопределенном состоянии, где вы можете либо назначить его, либо уничтожить. ССЗ function реализация делает именно это: только _M_manager важно, насколько управление ресурсами вовлечено, остальное (включая _M_invoker) — это просто «удобные» указатели.

Я вырыл достаточно далеко в GCC function реализация не имеет абсолютно никаких сомнений в отношении статуса ложно положительный из clangДиагностика. Но так как у меня есть буквально сотни мест, где это происходит в моем коде, это делает просмотр результатов статического анализатора довольно болезненным, если не сказать больше.

Как я могу наставлять clang не сообщать об этой самой проблеме?

Опять же, если вы пропустили это, я использую clang 3.3 наряду с GCC libstdc++ 4.8.1,


Замечания: Если вы работаете clang 3.4 построить и если это не вызывает этот ложный позитив, пожалуйста, дайте мне знать. Насколько я пытался, я не смог запустить 3.4 на своей системе (Debian Jessie), но если это решит эту проблему, я просто попробую больше.

4

Решение

Это может быть интересно для вас:
Будущие направления для анализатора

По сути, в настоящее время вы можете отключить только определенные контролеры для TU или использовать

#ifndef __clang_analyzer__
...
#endif

если вам действительно нужно. Но, конечно, фактические ложные срабатывания должны сообщаться.

0

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

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

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector