stl sort的不当使用会概率造成core dump, 这个问题已经说过好几次, 如果不防范, 一旦遇到, 比较难查出原因。

来看看有问题的代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool compare(int a, int b)
    return a >= b;
int main(int argc, char *argv[])
    vector<int> vec;
    for (int i = 0; i < 17; i++)
        int x = 0;
        vec.push_back(x);
    sort(vec.begin(), vec.end(), compare);
    return 0;

     之前说过了, compare必须针对相等返回false,  显然, 上面程序中, 当a和b相等时, compare返回了true,  这是有问题的, 来看看:

ubuntu@VM-0-15-ubuntu:~/taoge/cpp$ g++ -g test.cpp
ubuntu@VM-0-15-ubuntu:~/taoge/cpp$ ./a.out 
Segmentation fault
ubuntu@VM-0-15-ubuntu:~/taoge/cpp$ 

      程序core dump了, 可以直接gdb a.out  core分析搞起(a.out不会运行), 也可以直接用gdb a.out挂着进程来再次运行一次:

ubuntu@VM-0-15-ubuntu:~/taoge/cpp$ gdb a.out 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...done.
(gdb) 
(gdb) 
(gdb) 
(gdb) r
Starting program: /home/ubuntu/taoge/cpp/a.out 
Program received signal SIGSEGV, Segmentation fault.
0x000000000040219f in __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(int, int)>::operator()<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > > (
    this=0x7fffffffe1a0, __it1=<error reading variable: Cannot access memory at address 0x638000>, __it2=0)
    at /usr/include/c++/5/bits/predefined_ops.h:123
123             { return bool(_M_comp(*__it1, *__it2)); }
(gdb) 
(gdb) 
(gdb) 
(gdb) bt
#0  0x000000000040219f in __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(int, int)>::operator()<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > > (
    this=0x7fffffffe1a0, __it1=<error reading variable: Cannot access memory at address 0x638000>, __it2=0)
    at /usr/include/c++/5/bits/predefined_ops.h:123
#1  0x000000000040207c in std::__unguarded_partition<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(int, int)> > (__first=<error reading variable: Cannot access memory at address 0x638000>, 
    __last=0, __pivot=0, __comp=...) at /usr/include/c++/5/bits/stl_algo.h:1897
#2  0x0000000000401a6d in std::__unguarded_partition_pivot<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(int, int)> > (__first=0, __last=0, __comp=...)
    at /usr/include/c++/5/bits/stl_algo.h:1918
#3  0x00000000004016d0 in std::__introsort_loop<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, long, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(int, int)> > (__first=0, __last=0, __depth_limit=13, __comp=...)
    at /usr/include/c++/5/bits/stl_algo.h:1948
#4  0x00000000004012c9 in std::__sort<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(int, int)> > (__first=0, __last=0, __comp=...) at /usr/include/c++/5/bits/stl_algo.h:1963
#5  0x0000000000400de0 in std::sort<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, bool (*)(int, int)> (__first=0, __last=0, __comp=0x400aa6 <compare(int, int)>) at /usr/include/c++/5/bits/stl_algo.h:4729
#6  0x0000000000400b41 in main (argc=1, argv=0x7fffffffe448) at test.cpp:21
(gdb) 

        能看到进程调用栈, 进入帧1看看:

(gdb) f 1
#1  0x000000000040207c in std::__unguarded_partition<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(int, int)> > (__first=<error reading variable: Cannot access memory at address 0x638000>, 
    __last=0, __pivot=0, __comp=...) at /usr/include/c++/5/bits/stl_algo.h:1897
1897              while (__comp(__first, __pivot))
(gdb) i args
__first = <error reading variable __first (Cannot access memory at address 0x638000)>
__last = 0
__pivot = 0
__comp = {_M_comp = 0x400aa6 <compare(int, int)>}
(gdb) p *--__first
$6 = (int &) @0x637ffc: 0
(gdb) 

       可见, __first越界了, 而--__first刚好没有越界, 其对应的值为0,  所以, 内存越界导致了core dump, 这个时候, 走入__unguarded_partition的逻辑, 其代码为:

/// This is a helper function...  
  template<typename _RandomAccessIterator, typename _Tp, typename _Compare>  
    _RandomAccessIterator  
    __unguarded_partition(_RandomAccessIterator __first,  
              _RandomAccessIterator __last,  
              _Tp __pivot, _Compare __comp)  
      while (true)  
      while (__comp(*__first, __pivot))  
        ++__first;  
      --__last;  
      while (__comp(__pivot, *__last))  
        --__last;  
      if (!(__first < __last))  
        return __first;  
      std::iter_swap(__first, __last);  
      ++__first;  

       假设待排序的所有元素值都是0, 而我们自定义的compare对于相等返回true, 所以如下代码会一直运行

      while (__comp(*__first, __pivot))  
        ++__first;  

        直到__first越界, 而*__first就形成了越界访问。 回顾一下, gdb调试的时候, 发现*--__first的值为0, 可见__first刚刚越界一点点,刚好出轨。

       上面的compare只有在特定情况下才会越界, 所以体现出概率性core dump.   如果所有的值不等, 则不一定会core dump. 另外, 如果把上面的程序的17改了16, 程序就不会core dump了, 因为:

template<typename _RandomAccessIterator>  
    void __final_insertion_sort(_RandomAccessIterator __first,  
                   _RandomAccessIterator __last) {  
        if (__last - __first > _S_threshold)  
            __insertion_sort(__first, __first + _S_threshold);  
            __unguarded_insertion_sort(__first + _S_threshold, __last);  
        else __insertion_sort(__first, __last);  

      而_S_threshold的值正是16:

	enum { _S_threshold = 16 };

      有兴趣的可以继续看看sort的源码, 不难分析出上述问题的根源。

      好几个朋友都遇到过, 所以今天再来说一下。

stl sort的不当使用会概率造成core dump, 这个问题已经说过好几次, 如果不防范, 一旦遇到, 比较难查出原因。 来看看有问题的代码:#include &amp;lt;iostream&amp;gt;#include &amp;lt;vector&amp;gt;#include &amp;lt;algorithm&amp;gt;using namespace std;bool compare(i...
最近, 一位同学在开发中遇到了core dump问题, 当时没有看出来, 后来请某哥帮看, 我在旁边听他们的分析与讨论, 无意中听到了“排序”这个字眼, 于是就有点敏感了, 凑过去一看, 果然是stl sort coredump问题。         于是, 让那位同学改一下, 果然就没有coredump问题了, 哈哈!         详细信息请参考我博文之前介绍过的stl sort cor
前两天和阿彬扯淡的时候(注意不是扯蛋),他自己一个礼拜解决了三个Core dump,华丽丽之极,让我对其敬仰、膜拜之情如滔滔之江水,绵绵不绝。今天我也来谈一下Linux环境下开发时经常遇到的“Segmetation fault”的一点点个人看法,也算是抛砖引玉了。    (备注:我的glibc版本是2.12,GCC版本4.4.6,内核版本2.6.32-279)    Linux上开发时最
STL 中,weak_ptr 用于在不希望增加对象引用计数的情况下,对 shared_ptr 进行引用。这在某些情况下很有用,因为它允许我们在避免循环引用的同时,仍然可以在必要时访问共享对象。 举个例子,假设有两个类 A 和 B,其中 A 中有一个 shared_ptr 指向 B,而 B 中又有一个 shared_ptr 指向 A。这样导致循环引用,使得 A 和 B 的引用计数都永远不归零。这种情况下,我们可以在 A 中使用 weak_ptr 来引用 B,从而避免循环引用,使得 A 和 B 的引用计数可以正常地归零,从而达到资源的正常释放。