4

我在 gcc 10 上尝试使用 -fanalyzer,并设法在 std::vector 中报告了一个空指针取消引用。但我不确定我的代码是否有错误?

#include <vector>

class Bar
{
public:
    explicit Bar()
    {
    }
    int m_val;
};

int main()
{
    std::vector<Bar> a;
    std::vector<Bar> b(a);
    static_cast<void>(b);
    return 0;
}

它只会因 -O2(或 -O -O1 -O3)而失败

g++-10 -fanalyzer TestVector.cpp -O2
In copy constructor ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = Bar; _Alloc = std::allocator<Bar>]’:                                                                     
cc1plus: warning: dereference of NULL ‘__cur’ [CWE-690] [-Wanalyzer-null-dereference]                                                                                                                       
  ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = Bar; _Alloc = std::allocator<Bar>]’: events 1-2                                                                            
    |                                                                                                                                                                                                       
    |/usr/include/c++/10/bits/stl_vector.h:553:7:                                                                                                                                                           
    |  305 |       { _M_create_storage(__n); }                                                                                                                                                              
    |      |         ~~~~~~~~~~~~~~~~~~~~~~                                                                                                                                                                 
    |      |                          |                                                                                                                                                                     
    |      |                          (2) calling ‘std::_Vector_base<Bar, std::allocator<Bar> >::_M_create_storage’ from ‘std::vector<Bar>::vector’
    |......
    |  553 |       vector(const vector& __x)
    |      |       ^~~~~~
    |      |       |
    |      |       (1) entry to ‘std::vector<Bar>::vector’
    |
    +--> ‘void std::_Vector_base<_Tp, _Alloc>::_M_create_storage(std::size_t) [with _Tp = Bar; _Alloc = std::allocator<Bar>]’: events 3-5
           |
           |  346 |  return __n != 0 ? _Tr::allocate(_M_impl, __n) : pointer();
           |      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |                  |
           |      |                  (4) following ‘false’ branch (when ‘__n == 0’)...
           |......
           |  359 |       _M_create_storage(size_t __n)
           |      |       ^~~~~~~~~~~~~~~~~
           |      |       |
           |      |       (3) entry to ‘std::_Vector_base<Bar, std::allocator<Bar> >::_M_create_storage’
           |  360 |       {
           |  361 |  this->_M_impl._M_start = this->_M_allocate(__n);
           |      |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |                         |
           |      |                         (5) ...to here
           |
    <------+
    |
  ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = Bar; _Alloc = std::allocator<Bar>]’: events 6-7
    |
    |  305 |       { _M_create_storage(__n); }
    |      |         ~~~~~~~~~~~~~~~~~^~~~~
    |      |                          |
    |      |                          (6) returning to ‘std::vector<Bar>::vector’ from ‘std::_Vector_base<Bar, std::allocator<Bar> >::_M_create_storage’
    |......
    |  558 |    std::__uninitialized_copy_a(__x.begin(), __x.end(),
    |      |    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                               |
    |      |                               (7) ‘&lt;unknown>’ is NULL
    |  559 |           this->_M_impl._M_start,
    |      |           ~~~~~~~~~~~~~~~~~~~~~~~
    |  560 |           _M_get_Tp_allocator());
    |      |           ~~~~~~~~~~~~~~~~~~~~~~
    |
  ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = Bar; _Alloc = std::allocator<Bar>]’: event 8
    |
    |/usr/include/c++/10/bits/stl_uninitialized.h:90:23:
    |   90 |        for (; __first != __last; ++__first, (void)++__cur)
    |      |               ~~~~~~~~^~~~~~~~~
    |      |                       |
    |      |                       (8) following ‘true’ branch...
    |
  ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = Bar; _Alloc = std::allocator<Bar>]’: event 9
    |
    |/usr/include/c++/10/bits/stl_iterator.h:980:2:
    |  980 |  ++_M_current;
    |      |  ^~
    |      |  |
    |      |  (9) ...to here
    |
  ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = Bar; _Alloc = std::allocator<Bar>]’: event 10
    |
    |cc1plus:
    | (10): dereference of NULL ‘__cur’
    |

g++-10 -fanalyzer TestVector.cpp -O0编译得很好。

从 Bar 中删除 m_val 或构造函数也可以正常编译。

$ g++-10 --version
g++-10 (Ubuntu 10.1.0-2ubuntu1~18.04) 10.1.0

现场演示

4

2 回答 2

3

您的代码不负责。海湾合作委员会是。

有人在gcchelp邮件列表上报告了类似的问题, Wakely先生的回复是:

分析器尚不支持 C++ 是一个已知限制。

在我看来,它似乎错误地跟随了“真”分支,尽管这很有趣,因为条件运算符不是 C++ 独有的。

不幸的是,分析器的这一事实似乎没有记录在案,至少没有描述开关的位置

于 2020-10-29T16:18:27.120 回答
2

但我不确定我的代码是否有错误?

你的代码很好。

在这种情况下,警告来自标准库。有两个可能的原因:标准库实现有错误,或者警告是误报。

于 2020-10-29T16:13:42.153 回答