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.
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 tooperator new(std::size_t)
oroperator 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With