5

I tracked a bug to the use of a __m128 (SSE vector) as a value in a std::unordered_map. This causes a runtime segmentation fault with mingw32 g++4.7.2.

Please see the example below. Is there any reason why this should fail? Or, might there be a workaround? (I tried wrapping the value in a class but it did not help.) Thanks.

#include <unordered_map>
#include <xmmintrin.h>          // __m128
#include <iostream>

int main()
{
    std::unordered_map<int,__m128> m;
    std::cerr << "still ok\n";
    m[0] = __m128();
    std::cerr << "crash in previous statement\n";
    return 0;
}

Compilation settings: g++ -march=native -std=c++11

Hugues
  • 2,865
  • 1
  • 27
  • 39
  • 1
    Some related reading here: http://stackoverflow.com/questions/4424741/aligned-types-and-passing-arguments-by-value – Joe Feb 02 '13 at 18:18
  • When you dereference a pointer to a `__m128` type, the resulting load/store functions that the compiler emits are typically of the aligned variety, so it's making the inherent assumption that the underlying memory is aligned as needed for the type (16-byte alignment in this case). I'm guessing that somewhere in the container code, a pointer to an `__m128` is being dereferenced and the alignment assumption doesn't hold, resulting in a segmentation fault. If you run your program with a debugger and inspect the pointer value after the crash, you should be able to see this. – Jason R Feb 02 '13 at 18:59
  • Isn't any access to `m[0]` undefined behaviour anyway? – Gunther Piez Feb 02 '13 at 22:35
  • I hope the access to `m[0]` isn't intended to be special; I use it throughout my code; do you have any pointers that suggest `key==0` is reserved? – Hugues Feb 03 '13 at 06:18

2 Answers2

3

There are 2 issues regarding alignment:

Does the ABI ensure that __m128 variables are always aligned on the stack?

Does the global new operator return memory suitably aligned for the __m128 type? i.e., returns memory with a 16-byte alignment.

Brett Hale
  • 21,653
  • 2
  • 61
  • 90
  • 2
    Thanks for the feedback; it is definitely an alignment problem. It seems that the STL containers should be designed to respect the alignment attributes of the elements. Probably for now this requires a custom memory allocator? – Hugues Feb 03 '13 at 06:21
2

C++ currently doesn't handle dynamic allocation of over-aligned types. With usual x86 ABIs, standard alignment is 8 and __m128 has an alignment of 16 bytes, so it is overaligned. With usual x86_64 ABIs, the standard alignment is 16 which makes __m128 safe (but __m256 is unsafe again with its 32-byte alignment).

See this paper for a possible change in the next standard that would make things "just work": http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3396.htm

In the meantime, you can specify your own allocator, for instance based on aligned_alloc (C11), posix_memalign (unix), _aligned_malloc (Microsoft), etc.

Hugues
  • 2,865
  • 1
  • 27
  • 39
Marc Glisse
  • 7,550
  • 2
  • 30
  • 53