Std: nth_element crash
(1) Source Code:
- 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) Problem:
Crash occurs frequently. The stack is as follows:
- #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 (__a=..., __b=...) at /usr/local/include/c++/4.8.2/bits/move.h:177
- #3 0x000000000052e0b0 in std::iter_swap<__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > > > (__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, miuifs::BlockManager::ChooseWritableMirroringGroups(std::vector *, int)::__lambda101>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, 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 >, miuifs::BlockManager::ChooseWritableMirroringGroups(std::vector *, int)::__lambda101>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, 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 >, long int, miuifs::BlockManager::ChooseWritableMirroringGroups(std::vector *, int)::__lambda101>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, 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 >, miuifs::BlockManager::ChooseWritableMirroringGroups(std::vector *, int)::__lambda101>(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, 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 , mgs=0x7fffeb9f4140,
- copy_count=2) at miuifs/miuistorage-dev/BlockManager.cc:391
- #9 0x00000000005ff9cf in miuifs::BlockManager::NewBlock (this=0x118abe0 ) at miuifs/miuistorage-dev/BlockManager.cc:331
- #10 0x00000000005fed63 in miuifs::BlockManager::AcquireBlock (this=0x118abe0 , attribute=...)
- at miuifs/miuistorage-dev/BlockManager.cc:243
(3) Search for problems:
The problem has been found in std: nth_element. At first, I didn't think of the STL problem, and there was no good solution, later, I found the cause by reading the STL source code in/usr/local/include/c ++/4.8.2/bits/stl_algo.h:
- template
- 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);
- }
The _ move_median_to_first function exchanges the values of the intermediate sizes in _ first + 1, _ mid, (_ last-2) with _ first. However, the _ mid (_ last-2) point to the same iterator is ignored. If the input is as follows:
The result after _ move_median_to_first is as follows:
_ First points to the maximum value. Then, let's take a look at the implementation of std ::__ unguarded_partition. In row 2263 _ comp (* _ first, _ partition), true is always returned, as a result, ++ _ first has been executed and illegal memory is accessed.
- template
- _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) solution:
Google found the following link and found that it was indeed a STL bug. It could only be solved by upgrading C ++.
Https://bugs.debian.org/cgi-bin/bugreport.cgi? Bug = 732042