std::stable_sort() and std::get_temporary_buffer() of libstdc++ ignore alignment
Summary
This is NOT an Eigen bug, but an already reported libstdc++ one: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105258
Reporting this here, too, to point people having the issue in the right direction.
The issue occurs when using Eigen types (or structs containing them) with std::stable_sort()
or std::get_temporary_buffer()
of libstdc++. Seems to only cause obvious faults when compiled to NEON vector instructions.
Environment
- Operating System : Linux
- Architecture : ARMv7a with NEON
- Eigen Version : 3.4
- Compiler Version : Debian clang version 11.0.1-2
- Compile Flags : --target=armv7a-linux-gnueabihf -mcpu=cortex-a9 -mthumb -mfpu=neon-fp16
- Vector Extension : NEON
Minimal Example
https://godbolt.org/z/1TxcTzz53
See the assembly of clang for Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >::PlainObjectBase(Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&&)
which uses vst1.64 {d16, d17}, [r0:128]
. This is where the exception will occur at runtime. The GCC assembly does not contain vector instructions and DOES NOT trigger the issue.
Steps to reproduce
- clang-build for ARM with NEON (which has strict alignment requirements on the vector instructions)
- run repeatedly (memory may be correctly aligned occasionally)
What is the current bug behavior?
Terminate with SIGBUS.
What is the expected correct behavior?
Not crashing.
Relevant logs
Journal says something like
kernel: Alignment trap: not handling instruction f9400aef at [<0033fd22>]
kernel: 8<--- cut here ---
kernel: Unhandled fault: alignment exception (0x811) at 0x0039e538
kernel: pgd = f702d2df
kernel: [0039e538] *pgd=0fee1831, *pte=1e5cc75f, *ppte=1e5ccc7f
gdb says something like
Catchpoint 1 (signal SIGBUS), 0x0033fd26 in Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >::PlainObjectBase(Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&&) ()
(gdb) bt
#0 0x0033fd26 in Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >::PlainObjectBase(Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&&) ()
#1 0x0033fcf0 in Eigen::Matrix<double, 2, 1, 0, 2, 1>::Matrix(Eigen::Matrix<double, 2, 1, 0, 2, 1>&&) ()
#2 0x0033fcbe in PointValPair::PointValPair(PointValPair&&) ()
#3 0x0033fc72 in void std::_Construct<PointValPair, PointValPair>(PointValPair*, PointValPair&&) ()
#4 0x0033fbb8 in void std::__uninitialized_construct_buf_dispatch<false>::__ucr<PointValPair*, PointValPair*>(PointValPair*, PointValPair*, PointValPair*) ()
#5 0x0033fae0 in void std::__uninitialized_construct_buf<PointValPair*, PointValPair*>(PointValPair*, PointValPair*, PointValPair*) ()
#6 0x0033f896 in std::_Temporary_buffer<PointValPair*, PointValPair>::_Temporary_buffer(PointValPair*, int) ()
#7 0x0033f7ca in void std::__stable_sort<PointValPair*, __gnu_cxx::__ops::_Iter_less_iter>(PointValPair*, PointValPair*, __gnu_cxx::__ops::_Iter_less_iter) ()
#8 0x0033f77a in void std::stable_sort<PointValPair*>(PointValPair*, PointValPair*) ()
Anything else that might help
-
wait for libstdc++ to fix their bug (i.e. https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_tempbuf.h#L113 should not allocate raw memory without alignment and then cast to destination type) -
workaround use boost::sort::spinsort()
instead ofstd::stable_sort()