id,summary,reporter,owner,description,type,status,milestone,component,version,severity,resolution,keywords,cc 13635,circular_buffer does not always initialize elements,Niklas Fejes ,Jan Gaspar,"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}}}. {{{#!c++ 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: {{{#!c++ 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: {{{#!c++ #include #include /* $ 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 x(7), y(8); // has non-trivial move/copy boost::circular_buffer< std::vector > 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 } }}}",Bugs,new,To Be Determined,circular_buffer,Boost Development Trunk,Problem,,,