std::nth_element bug引起的crash问题
来源:互联网 发布:优化出口商品结构 编辑:程序博客网 时间:2024/05/18 01:12
(1) 源码:
auto less_compare = [] (const MirroringGroup& mg1, const MirroringGroup& mg2) -> bool { return (mg1.usage() < mg2.usage());};std::nth_element(mgs->begin(), mgs->begin() + (copy_count - 1), mgs->end(), less_compare);
(2) 问题:
经常发生crash,stack如下:
#0 0x00000000004b3807 in MirroringGroup::CopyFrom (this=0x15edf20, from=...) at miuifs/miuistorage-dev/idl/proto/InternalData.pb.cc:6487#1 0x000000000052bc71 in MirroringGroup::operator= (this=0x15edf20, from=...) at miuifs/miuistorage-dev/idl/proto/InternalData.pb.h:1797#2 0x000000000052f7cb in std::swap<MirroringGroup> (__a=..., __b=...) at /usr/local/include/c++/4.8.2/bits/move.h:177#3 0x000000000052e0b0 in std::iter_swap<__gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, __gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > > > (__a=..., __b=...) at /usr/local/include/c++/4.8.2/bits/stl_algobase.h:147#4 0x0000000000604b11 in std::__unguarded_partition<__gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup> >, MirroringGroup, miuifs::BlockManager::ChooseWritableMirroringGroups(std::vector<MirroringGroup>*, int)::__lambda101>(__gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, __gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, const MirroringGroup &, miuifs::BlockManager::__lambda101) (__first=..., __last=..., __pivot=..., __comp=...) at /usr/local/include/c++/4.8.2/bits/stl_algo.h:2270#5 0x0000000000603c1b in std::__unguarded_partition_pivot<__gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup> >, miuifs::BlockManager::ChooseWritableMirroringGroups(std::vector<MirroringGroup>*, int)::__lambda101>(__gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, __gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, miuifs::BlockManager::__lambda101) ( __first=..., __last=..., __comp=...) at /usr/local/include/c++/4.8.2/bits/stl_algo.h:2296#6 0x0000000000603408 in std::__introselect<__gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup> >, long int, miuifs::BlockManager::ChooseWritableMirroringGroups(std::vector<MirroringGroup>*, int)::__lambda101>(__gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, __gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, __gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, long, miuifs::BlockManager::__lambda101) (__first=..., __nth=..., __last=..., __depth_limit=2, __comp=...) at /usr/local/include/c++/4.8.2/bits/stl_algo.h:2394#7 0x0000000000602c95 in std::nth_element<__gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup> >, miuifs::BlockManager::ChooseWritableMirroringGroups(std::vector<MirroringGroup>*, int)::__lambda101>(__gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, __gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, __gnu_cxx::__normal_iterator<MirroringGroup*, std::vector<MirroringGroup, std::allocator<MirroringGroup> > >, miuifs::BlockManager::__lambda101) (__first=..., __nth=..., __last=..., __comp=...) at /usr/local/include/c++/4.8.2/bits/stl_algo.h:5417#8 0x000000000060039c in miuifs::BlockManager::ChooseWritableMirroringGroups (this=0x118abe0 <miuifs::BlockManager::Instance()::instance>, mgs=0x7fffeb9f4140, copy_count=2) at miuifs/miuistorage-dev/BlockManager.cc:391#9 0x00000000005ff9cf in miuifs::BlockManager::NewBlock (this=0x118abe0 <miuifs::BlockManager::Instance()::instance>) at miuifs/miuistorage-dev/BlockManager.cc:331#10 0x00000000005fed63 in miuifs::BlockManager::AcquireBlock (this=0x118abe0 <miuifs::BlockManager::Instance()::instance>, attribute=...) at miuifs/miuistorage-dev/BlockManager.cc:243
(3) 查找问题:
问题一直出现在std::nth_element中,开始没有想到是STL的问题,一直没有很好的解决办法,后来通过阅读STL源码找到原因在/usr/local/include/c++/4.8.2/bits/stl_algo.h中:
template<typename _RandomAccessIterator, typename _Compare> inline _RandomAccessIterator __unguarded_partition_pivot(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) { _RandomAccessIterator __mid = __first + (__last - __first) / 2; std::__move_median_to_first(__first, __first + 1, __mid, (__last - 2), __comp); return std::__unguarded_partition(__first + 1, __last, *__first, __comp); }
__move_median_to_first函数的作用是将 __first +1 , __mid, (__last - 2)中中间大小的值和 __first交换。但是却忽略了__mid,(__last - 2)指向相同迭代器的情况,如果输入时情况如下:
经过__move_median_to_first之后的结果如下:
此时__first指向了最大的值。然后看std::__unguarded_partition的实现,在2263行__comp(*__first, __pivot))永远返回true,导致++__first一直执行而访问了非法内存。
template<typename _RandomAccessIterator, typename _Tp, typename _Compare> _RandomAccessIterator __unguarded_partition(_RandomAccessIterator __first, _RandomAccessIterator __last, const _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; } }
(4) 解决方法:
通过google找到下面这个链接,发现确实是一个STL的bug,只能通过升级C++解决了。
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=732042
1 0
- std::nth_element bug引起的crash问题
- std::string crash的问题
- ARMv8引起的crash问题
- std::nth_element
- 有关nth_element的问题
- 异步事件引起的plugins crash问题
- 小问题引起的bug
- std::string引用计数引起的问题
- std::nth_element 排序
- haslayout 问题引起的常见 bug
- crash引起播放列表退出的问题分析过程分享
- 一个lua代码中的bug引起的思考:不要被c++ crash堆栈误导
- std::lock_guard 引起的思考
- unsigned引起的bug
- typedef引起的bug
- OpenCppCoverage 引起测试程序Crash问题
- C# 修正DataGrid bug引起的问题及反思
- 关于flash擦除引起的bug问题小结
- mysql表空间总结
- linux 编译内核[scripts/kconfig/dochecklxdialog] 错误
- http://blog.csdn.net/hguisu/article/details/8836819
- Date类型的实体类属性中,Date必须是Java.util.Date,而不能是Java.sql.Date
- 尝试参加阿里云 天池 大赛 (看看odps到底封装的多好)1,本地跑通了。2、把mr程序上传到御膳房
- std::nth_element bug引起的crash问题
- MD5加密
- tomcat详解
- iOS: 如何判断代码运行在DEBUG还是RELEASE模式下?
- HDU-1950-Bridging signals【最长上升子序列(LIS)长度的O(nlogn)算法】
- javascript div动态大小改变
- Swift String 扩展
- Linux-export‘ ’not a valid identifier 的一般原因
- 程序阻碍OD调试的方式1