Search code examples
c++simdrelease-modedirectxmath

Using XMVECTOR from DirectXMath as a class member causes a crash only in Release Mode?


I've been trying to use XMVECTOR as a class member for a bounding box, since I do a lot of calculations, but I use the XMFLOAT3 only once per frame, so the bounding box has a method that gives me it's center in a XMFLOAT3, otherwise it stays in a XMVECTOR;The class is delcared with __declspec(align(16)) and works in debug mode.However in Release mode it crashes the instant I set it to something:

    Box& Box::operator=(const Box& box)
    {
        _center = box._center;
        _extents = box._extents;
        return *this;
    }

Whenever I do:

Box A;

Box B;

A = B;

It crashes, giving me 0xC0000005: Access violation reading location 0x00000000. Also it crashes when I create it as a pointer:

Box* A = new Box();

This is the constructor:

    Box::Box()
    {
        center = XMVectorZero();
        extents = XMVectorSplatOne();
    }

Again, this works fine in Debug mode, but in Release it crashes.What could Release mode be changing that would generate invalid code?Do I need to do something else, other than aligning the box to 16 bytes?


Solution

  • The class is not being created at an aligned address, so even though the XM* members are aligned on 16-byte boundaries, the parent's alignment miss-aligns them, causing the crash.

    To prevent this you need to use _mm_alloc (which really just wraps _aligned_alloc), or replace the default allocator with one that returns blocks minimally aligned to 16 bytes (under x64 this the case with the default allocator).

    a simple solution to this in C++ is to create a base class for all classes the contain XM* members that looks like the following:

    template<size_t Alignment> class AlignedAllocationPolicy
    {
        public:
        static void* operator new(size_t size)
        {
            return _aligned_malloc(size,Alienment);
        }
    
        static void operator delete(void* memory)
        {
            _aligned_free(memory);
        }
    };
    
    class MyAlignedObject : public AlignedAllocationPolicy<16>
    {
    //...
    };
    

    As pointed out by @Dave, this is a minimal example, you'd want to overload all the new and delete operators, specifically new[] and delete[]