Opened 4 years ago
Last modified 4 years ago
#13635 new Bugs
circular_buffer does not always initialize elements
Reported by: | Owned by: | Jan Gaspar | |
---|---|---|---|
Milestone: | To Be Determined | Component: | circular_buffer |
Version: | Boost Development Trunk | Severity: | Problem |
Keywords: | Cc: |
Description
The circular_buffer erroneously mark some sections of the buffer as initialized, which can lead to use of uninitialized memory for non-trivial classes in the insert
function. The problem appears to come from the is_uninitialized
function, which does not properly handle the buffer state when m_buff < m_first < m_last
.
bool is_uninitialized(const_pointer p) const BOOST_NOEXCEPT { return p >= m_last && (m_first < m_last || p < m_first); }
In this case, e.g. p = m_buff
will be flagged as initialized since p >= m_last
is false
.
A proper check would be:
bool is_uninitialized(const_pointer p) const BOOST_NOEXCEPT { if (m_first < m_last) return p >= m_last || p < m_first; return p >= m_last && p < m_first; }
Minimal reproducing program:
#include <vector> #include <boost/circular_buffer.hpp> /* $ g++ --version | head -n1 g++ (GCC) 8.1.1 20180531 $ g++ example.cpp -o example && valgrind --tool=memcheck ./example 2>&1 | grep Invalid ==19349== Invalid write of size 8 ==19349== Invalid write of size 2 ==19349== Invalid free() / delete / delete[] / realloc() */ int main() { std::vector<int> x(7), y(8); // has non-trivial move/copy boost::circular_buffer< std::vector<int> > buffer(3); buffer.push_back(x); // [x| | ] buffer.push_back(x); // [x|x| ] buffer.pop_front(); // [ |x| ] buffer.insert(buffer.begin(), 2, y); // is_uninitialized(i) -> [0,0,1] (should be [1,0,1]) // [copy 1 -> 0] : [x|x| ] bad copy to uninitialized element // [copy y -> 1] : [x|y| ] ok // [construct y -> 2] : [x|y|y] ok return 0; // tries to destruct uninitialized entry }
Note:
See TracTickets
for help on using tickets.
Submitted pull request at: https://github.com/boostorg/circular_buffer/pull/17