Overloading operator new with smaller default alignment

左心房为你撑大大i 提交于 2021-02-18 11:18:05

问题


C++17 introduced Dynamic memory allocation for over-aligned data

Beside the existing std::max_align_t, the fundamental alignment, it added __STDCPP_DEFAULT_NEW_ALIGNMENT__ the minimal alignment that the operator new guarantees.

With MSVC2017 64bit compilation, these constants result in a std::max_align_t of size 8 and __STDCPP_DEFAULT_NEW_ALIGNMENT__ of size 16.

It is however allowed to overrule the operator new/free, as mentioned on cppreference: operator new - global replacements.

Looking at all of the documents, it's unclear to me if this function is allowed to provide a new default alignment and if so, if we are allowed to redefine this constant.

An example for illustration:

#include <new>
#include <iostream>
#include <cassert>
#include <cstdint>
#include <cstddef>

static_assert(alignof(std::max_align_t) == 8);
static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ == 16);


void * operator new(size_t size) 
{ 
    std::cout << "New operator overloading " << std::endl; 
    void * p = std::malloc((size == 8) ? 16 : size); 
    assert(std::uintptr_t(p)%16 == 0);
    if (size == 8)
        {
        auto correctedPtr = std::uintptr_t(p) + 8;
        return (void*)correctedPtr;
        }
    return p; 
} 

void operator delete(void * p) 
{ 
    std::cout << "Delete operator overloading " << std::endl; 
    if (std::uintptr_t(p)%16 != 0)
    {
        auto correctedPtr = std::uintptr_t(p) - 8;
        std::free((void*)correctedPtr);
    }
    std::free(p); 
}

namespace
{
    struct D
    {
        double d;
    };
}


int main(int, char**)
{
    new D{};
    return 0;
}

Code at compiler explorer

The reason I'm asking this, is because I'm investigating crashes in an MSVC program that is now being compiled with Clang. Here we noticed that clang uses CPU instructions that rely on this 16 bit alignment in order to initialize a class of size 8.


回答1:


According to N4659 (last public draft for C++17):

6.7.4p3:

Any allocation and/or deallocation functions defined in a C++program, including the default versions in the library, shall conform to the semantics specified in 6.7.4.1 and 6.7.4.2.

6.7.4.1p2:

... The pointer returned shall be suitably aligned so that it can be converted to a pointer to any suitable complete object type (21.6.2.1) and then used to access the object or array in the storage allocated(until the storage is explicitly deallocated by a call to a corresponding deallocation function). ...

19.8p1:

The following macro names shall be defined by the implementation: ... __STDCPP_DEFAULT_NEW_ALIGNMENT__ An integer literal of type std::size_t whose value is the alignment guaranteed by a call to operator new(std::size_t) or operator new[](std::size_t). ...

19.8p4:

If any of the pre-defined macro names in this subclause, or the identifier defined, is the subject of a #define or a #undef preprocessing directive, the behavior is undefined. ...

So, you cannot change the __STDCPP_DEFAULT_NEW_ALIGNMENT__ value inside your program, and if your allocation function is called for alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__) type of size 8, you cannot detect that, but you still need to return a suitably aligned pointer.

Nonetheless, you can change the __STDCPP_DEFAULT_NEW_ALIGNMENT__ value as defined by clang itself using -fnew-alignment compiler option. Not sure if it helps in your case.



来源:https://stackoverflow.com/questions/56713868/overloading-operator-new-with-smaller-default-alignment

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!