std::sort引发的core (这个分析还是很不错的!!!)

本文介绍了一个由std::sort引发的段错误问题,并通过一个示例程序进行了复现。分析了STL排序算法中分区函数的实现细节,指出了比较函数在元素相等时返回true可能导致的内存访问越界问题。

        转载地址:http://blog.chinaunix.net/uid-23146151-id-3066266.html

 

        这两天定位了一个由std::sort引发的core。


写了下面的程序来复现此问题。
  1. #include <stdio.h>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <new>
  5.  
  6. struct foo_t
  7. {
  8.     int size;
  9. };
  10.  
  11. class cmp_t
  12. {
  13. public:
  14.     bool operator()(foo_t *a, foo_t *b)
  15.     {
  16.         return a->size >= b->size;
  17.     }
  18. };
  19.  
  20. int main(int argc, char *argv[])
  21. {
  22.     std::vector<foo_t *> vec;
  23.  
  24.     for (int i = 0; i < 17; i++)
  25.     {
  26.         foo_t *= new(std::nothrow) foo_t();
  27.         if (NULL == x)
  28.         {
  29.             goto fail;
  30.         }
  31.         else
  32.         {
  33.             x->size = 1;
  34.         }
  35.         vec.push_back(x);
  36.     }
  37.  
  38.     std::sort(vec.begin(), vec.end(), cmp_t());
  39. fail:
  40.     for(std::vector<foo_t *>::iterator iter = vec.begin(); vec.end() != iter; ++iter)
  41.     {
  42.         delete *iter;
  43.         *iter = NULL;
  44.     }
  45.  
  46.     return 0;
  47. }
然后编译
  1. g++ main.cpp -Werror -Wall -g
然后执行,此时系统出core,错误类型为段错误
如果无core文件产生,可以使用
  1. ulimit -c unlimited
后重新执行一次,此时就会有core文件生成
然后
  1. gdb a.out core
  2. (gdb) bt
  3. #0  0x0804889e in cmp_t::operator() (this=0xbfed92d0, a=0x0, b=0x9a9d0c8) at main.cpp:16
    #1  0x080497ff in std::__unguarded_partition<__gnu_cxx::__normal_iterator<foo_t**, std::vector<foo_t*,="" std::allocator > >, foo_t*, cmp_t> (__first=..., __last=..., __pivot=@0x9a9d1a0, __comp=...) at /usr/include/c++/4.6/bits/stl_algo.h:2233
    #2  0x0804926a in std::__unguarded_partition_pivot<__gnu_cxx::__normal_iterator<foo_t**, std::vector<foo_t*,="" std::allocator > >, cmp_t> (__first=..., __last=..., __comp=...) at /usr/include/c++/4.6/bits/stl_algo.h:2265
    #3  0x08048e84 in std::__introsort_loop<__gnu_cxx::__normal_iterator<foo_t**, std::vector<foo_t*,="" std::allocator > >, int, cmp_t> (
        __first=..., __last=..., __depth_limit=7, __comp=...) at /usr/include/c++/4.6/bits/stl_algo.h:2306
    #4  0x08048a22 in std::sort<__gnu_cxx::__normal_iterator<foo_t**, std::vector<foo_t*,="" std::allocator > >, cmp_t> (__first=..., 
        __last=..., __comp=...) at /usr/include/c++/4.6/bits/stl_algo.h:5368
    #5  0x080487ce in main (argc=1, argv=0xbfed9464) at main.cpp:38
     
可以看到,系统core在了排序函数里面。
然后通过分析stl代码发现以下一段代码
  1. /// This is a helper function...
  2.   template<typename _RandomAccessIterator, typename _Tp, typename _Compare>
  3.     _RandomAccessIterator
  4.     __unguarded_partition(_RandomAccessIterator __first,
  5.              _RandomAccessIterator __last,
  6.              const _Tp& __pivot, _Compare __comp)
  7.     {
  8.       while (true)
  9.     {
  10.      while (__comp(*__first, __pivot))
  11.      ++__first;
  12.      --__last;
  13.      while (__comp(__pivot, *__last))
  14.      --__last;
  15.      if (!(__first < __last))
  16.      return __first;
  17.      std::iter_swap(__first, __last);
  18.      ++__first;
  19.     }
  20.     }
此函数完成快速排序中分区功能,即将比哨兵小的数据放在其前,大的放在其后。
函数中使用的是
while (__comp(*__first, __pivot))
    ++__first;

如果当比较元素相同返回真时,此时比较元素将会继续向下遍历,在极端情况下,例如程序中所有元素都是一样的情况下,在这种情况下,就会出现访问越界,结果就是导致程序出现segment fault

所以在写c++ stl中的比较函数是,bool返回真的时候,一定是“真的”大,或者小,等于的时候只能返回false。


这个错误算是一次教训,所幸的是没有引起大范围的错误。

 

udo make -j8 Scanning dependencies of target opencv_highgui_plugins Scanning dependencies of target ittnotify Scanning dependencies of target quirc Scanning dependencies of target libprotobuf Scanning dependencies of target ade Scanning dependencies of target opencv_videoio_plugins Scanning dependencies of target gen_opencv_python_source [ 0%] Built target opencv_videoio_plugins [ 0%] Building C object 3rdparty/ittnotify/CMakeFiles/ittnotify.dir/src/ittnotify/ittnotify_static.c.o [ 0%] Built target opencv_highgui_plugins [ 0%] Building C object 3rdparty/quirc/CMakeFiles/quirc.dir/src/decode.c.o [ 0%] Building C object 3rdparty/quirc/CMakeFiles/quirc.dir/src/quirc.c.o [ 0%] Generate files for Python bindings and documentation [ 0%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/alloc.cpp.o [ 0%] Building C object 3rdparty/quirc/CMakeFiles/quirc.dir/src/version_db.c.o [ 0%] Building C object 3rdparty/ittnotify/CMakeFiles/ittnotify.dir/src/ittnotify/jitprofiling.c.o [ 0%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/assert.cpp.o [ 0%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/any_lite.cc.o [ 0%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/arena.cc.o [ 0%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/arenastring.cc.o [ 0%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/check_cycles.cpp.o [ 0%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/edge.cpp.o [ 0%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/execution_engine.cpp.o [ 0%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/extension_set.cc.o Note: Class Feature2D has more than 1 base class (not supported by Python C extensions) Bases: cv::Algorithm, cv::class, cv::Feature2D, cv::Algorithm Only the first base class will be used [ 0%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/generated_message_util.cc.o [ 1%] Linking C static library ../lib/libittnotify.a [ 1%] Built target ittnotify [ 1%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/graph.cpp.o [ 1%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/implicit_weak_message.cc.o Note: Class detail_GraphCutSeamFinder has more than 1 base class (not supported by Python C extensions) Bases: cv::detail::GraphCutSeamFinderBase, cv::detail::SeamFinder Only the first base class will be used [ 1%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/memory_accessor.cpp.o [ 2%] Linking C static library ../lib/libquirc.a [ 2%] Built target quirc [ 2%] Processing OpenCL kernels (core) Scanning dependencies of target opencv_core [ 2%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/io/coded_stream.cc.o [ 2%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/memory_descriptor.cpp.o [ 2%] Built target gen_opencv_python_source [ 2%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/io/io_win32.cc.o [ 2%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/io/strtod.cc.o [ 2%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/memory_descriptor_ref.cpp.o [ 2%] Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o [ 2%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/memory_descriptor_view.cpp.o [ 2%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/metadata.cpp.o [ 2%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/io/zero_copy_stream.cc.o [ 2%] Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/alloc.cpp.o [ 2%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/metatypes.cpp.o In file included from /home/z/下载/opencv-4.5.5/modules/core/include/opencv2/core/utility.hpp:56, from /home/z/下载/opencv-4.5.5/modules/core/src/precomp.hpp:53, from /home/z/下载/opencv-4.5.5/modules/core/src/algorithm.cpp:43: /home/z/下载/opencv-4.5.5/modules/core/include/opencv2/core.hpp: In function ‘cv::String& cv::operator<<(cv::String&, const cv::Mat&)’: /home/z/下载/opencv-4.5.5/modules/core/include/opencv2/core.hpp:3102:47: internal compiler error: 段错误 3102 | return out << Formatter::get()->format(mtx); | ^ [ 2%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/io/zero_copy_stream_impl.cc.o [ 3%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/node.cpp.o 0x7f2e0e35c08f ??? /build/glibc-FcRMwW/glibc-2.31/signal/../sysdeps/unix/sysv/linux/x86_64/sigaction.c:0 0x7f2e0e33d082 __libc_start_main ../csu/libc-start.c:308 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <file:///usr/share/doc/gcc-9/README.Bugs> for instructions. make[2]: *** [modules/core/CMakeFiles/opencv_core.dir/build.make:90:modules/core/CMakeFiles/opencv_core.dir/src/algorithm.cpp.o] 错误 1 make[2]: *** 正在等待未完成的任务.... [ 3%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/passes/communications.cpp.o [ 3%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/search.cpp.o [ 4%] Building CXX object 3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/io/zero_copy_stream_impl_lite.cc.o In file included from /usr/include/c++/9/istream:991, from /usr/include/c++/9/iostream:40, from /home/z/下载/opencv-4.5.5/3rdparty/protobuf/src/google/protobuf/io/zero_copy_stream_impl.cc:44: /usr/include/c++/9/bits/istream.tcc: In member function ‘std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::get(std::basic_istream<_CharT, _Traits>::char_type*, std::streamsize, std::basic_istream<_CharT, _Traits>::char_type)’: /usr/include/c++/9/bits/istream.tcc:326:66: internal compiler error: 段错误 326 | const int_type __idelim = traits_type::to_int_type(__delim); | ^ 0x7f0aca24708f ??? /build/glibc-FcRMwW/glibc-2.31/signal/../sysdeps/unix/sysv/linux/x86_64/sigaction.c:0 0x7f0aca228082 __libc_start_main ../csu/libc-start.c:308 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <file:///usr/share/doc/gcc-9/README.Bugs> for instructions. make[2]: *** [3rdparty/protobuf/CMakeFiles/libprotobuf.dir/build.make:193:3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/io/zero_copy_stream_impl.cc.o] 错误 1 make[2]: *** 正在等待未完成的任务.... [ 4%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/subgraphs.cpp.o [ 4%] Building CXX object CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/topological_sort.cpp.o during IPA pass: cp /home/z/下载/opencv-4.5.5/3rdparty/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.cc: In member function ‘virtual void google::protobuf::io::ArrayInputStream::BackUp(int)’: /home/z/下载/opencv-4.5.5/3rdparty/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.cc:467:1: internal compiler error: 段错误 467 | } // namespace google | ^ 0x7fe12677e08f ??? /build/glibc-FcRMwW/glibc-2.31/signal/../sysdeps/unix/sysv/linux/x86_64/sigaction.c:0 0x7fe12675f082 __libc_start_main ../csu/libc-start.c:308 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <file:///usr/share/doc/gcc-9/README.Bugs> for instructions. make[2]: *** [3rdparty/protobuf/CMakeFiles/libprotobuf.dir/build.make:206:3rdparty/protobuf/CMakeFiles/libprotobuf.dir/src/google/protobuf/io/zero_copy_stream_impl_lite.cc.o] 错误 1 make[1]: *** [CMakeFiles/Makefile2:1625:3rdparty/protobuf/CMakeFiles/libprotobuf.dir/all] 错误 2 make[1]: *** 正在等待未完成的任务.... In file included from /usr/include/c++/9/functional:54, from /home/z/下载/opencv-4.5.5/build/3rdparty/ade/ade-0.1.1f/sources/ade/include/ade/metatypes/metatypes.hpp:12, from /home/z/下载/opencv-4.5.5/build/3rdparty/ade/ade-0.1.1f/sources/ade/include/ade/passes/communications.hpp:14, from /home/z/下载/opencv-4.5.5/build/3rdparty/ade/ade-0.1.1f/sources/ade/source/passes/communications.cpp:7: /usr/include/c++/9/tuple: In instantiation of ‘constexpr _Head& std::__get_helper(std::_Tuple_impl<_Idx, _Head, _Tail ...>&) [with long unsigned int __i = 0; _Head = ade::MemoryDescriptorView* const&; _Tail = {}]’: /usr/include/c++/9/tuple:1321:36: required from ‘constexpr std::__tuple_element_t<__i, std::tuple<_Elements ...> >& std::get(std::tuple<_Elements ...>&) [with long unsigned int __i = 0; _Elements = {ade::MemoryDescriptorView* const&}; std::__tuple_element_t<__i, std::tuple<_Elements ...> > = ade::MemoryDescriptorView* const&]’ /usr/include/c++/9/tuple:1673:55: required from ‘std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {ade::MemoryDescriptorView* const&}; long unsigned int ..._Indexes1 = {0}; _Args2 = {}; long unsigned int ..._Indexes2 = {}; _T1 = ade::MemoryDescriptorView* const; _T2 = {anonymous}::CacheEntry]’ /usr/include/c++/9/tuple:1663:63: required from ‘std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {ade::MemoryDescriptorView* const&}; _Args2 = {}; _T1 = ade::MemoryDescriptorView* const; _T2 = {anonymous}::CacheEntry]’ /usr/include/c++/9/ext/new_allocator.h:146:4: required from ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<ade::MemoryDescriptorView* const, {anonymous}::CacheEntry>; _Args = {const std::piecewise_construct_t&, std::tuple<ade::MemoryDescriptorView* const&>, std::tuple<>}; _Tp = std::__detail::_Hash_node<std::pair<ade::MemoryDescriptorView* const, {anonymous}::CacheEntry>, false>]’ /usr/include/c++/9/bits/alloc_traits.h:483:4: required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::pair<ade::MemoryDescriptorView* const, {anonymous}::CacheEntry>; _Args = {const std::piecewise_construct_t&, std::tuple<ade::MemoryDescriptorView* const&>, std::tuple<>}; _Tp = std::__detail::_Hash_node<std::pair<ade::MemoryDescriptorView* const, {anonymous}::CacheEntry>, false>; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::__detail::_Hash_node<std::pair<ade::MemoryDescriptorView* const, {anonymous}::CacheEntry>, false> >]’ /usr/include/c++/9/bits/hashtable_policy.h:2086:36: required from ‘std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type* std::__detail::_Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<ade::MemoryDescriptorView* const&>, std::tuple<>}; _NodeAlloc = std::allocator<std::__detail::_Hash_node<std::pair<ade::MemoryDescriptorView* const, {anonymous}::CacheEntry>, false> >; std::__detail::_Hashtable_alloc<_NodeAlloc>::__node_type = std::__detail::_Hash_node<std::pair<ade::MemoryDescriptorView* const, {anonymous}::CacheEntry>, false>]’ /usr/include/c++/9/bits/hashtable_policy.h:701:8: required from ‘std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type& std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::operator[](const key_type&) [with _Key = ade::MemoryDescriptorView*; _Pair = std::pair<ade::MemoryDescriptorView* const, {anonymous}::CacheEntry>; _Alloc = std::allocator<std::pair<ade::MemoryDescriptorView* const, {anonymous}::CacheEntry> >; _Equal = std::equal_to<ade::MemoryDescriptorView*>; _H1 = std::hash<ade::MemoryDescriptorView*>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<false, false, true>; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::mapped_type = {anonymous}::CacheEntry; std::__detail::_Map_base<_Key, _Pair, _Alloc, std::__detail::_Select1st, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits, true>::key_type = ade::MemoryDescriptorView*]’ /usr/include/c++/9/bits/unordered_map.h:986:20: required from ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type& std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type&) [with _Key = ade::MemoryDescriptorView*; _Tp = {anonymous}::CacheEntry; _Hash = std::hash<ade::MemoryDescriptorView*>; _Pred = std::equal_to<ade::MemoryDescriptorView*>; _Alloc = std::allocator<std::pair<ade::MemoryDescriptorView* const, {anonymous}::CacheEntry> >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::mapped_type = {anonymous}::CacheEntry; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::key_type = ade::MemoryDescriptorView*]’ /home/z/下载/opencv-4.5.5/build/3rdparty/ade/ade-0.1.1f/sources/ade/source/passes/communications.cpp:91:22: required from here /usr/include/c++/9/tuple:1310:56: in ‘constexpr’ expansion of ‘std::_Tuple_impl<0, ade::MemoryDescriptorView* const&>::_M_head(__t)’ /usr/include/c++/9/tuple:1310:60: internal compiler error: 段错误 1310 | { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } | ^ 0x7f7630e1a08f ??? /build/glibc-FcRMwW/glibc-2.31/signal/../sysdeps/unix/sysv/linux/x86_64/sigaction.c:0 0x7f7630dfb082 __libc_start_main ../csu/libc-start.c:308 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <file:///usr/share/doc/gcc-9/README.Bugs> for instructions. make[2]: *** [CMakeFiles/ade.dir/build.make:232:CMakeFiles/ade.dir/3rdparty/ade/ade-0.1.1f/sources/ade/source/passes/communications.cpp.o] 错误 1 make[2]: *** 正在等待未完成的任务.... make[1]: *** [CMakeFiles/Makefile2:1801:modules/core/CMakeFiles/opencv_core.dir/all] 错误 2 make[1]: *** [CMakeFiles/Makefile2:1465:CMakeFiles/ade.dir/all] 错误 2 make: *** [Makefile:163:all] 错误 2
06-03
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值