Leeor
Leeor

Reputation: 19736

__attribute__((aligned(x)) doesn't work on dynamic allocations

I'm trying to build a simple linked list where each element would be aligned to some round address. I've tried the following code (shortened as much as possible to be SSCCE):

#include "stdio.h"
#define N 10

typedef struct  __attribute__((aligned(0x100)) _element {
  int val;
  char padding[64];
  struct _element *next;

}  element;


int main() {

    element* head = new element;
    element* current = head;
    for (int i = 0; i < N; ++i) {
        current->val = i;
        if (i == N - 1)
            break;
        current->next = new element;
        current = current->next;
    }
    current->next = NULL;

    current = head;
    printf("sizeof(element) = 0x%x\n", (unsigned int)sizeof(element));
    while (current) {
        printf("*(%p) = %d\n", &current->val, current->val);
        current = current->next;
    }

    return 0;
}

Built with g++ 4.2.2, no optimizations, and produced:

sizeof(element) = 0x100
*(0x501010) = 0
*(0x501120) = 1
*(0x501230) = 2
*(0x501340) = 3
*(0x501450) = 4
*(0x501560) = 5
*(0x501670) = 6
*(0x501780) = 7
*(0x501890) = 8
*(0x5019a0) = 9

Why aren't the addresses aligned to 0x100? Note that it did affect the struct "size", looks like it's being padded somehow, but it doesn't start at aligned addresses like I wanted.

From this answer I understood that there might be a max alignment, but even lowering it to 0x20 didn't change the alignment (only the sizeof). This answer doesn't help since it's about stack allocation. Couldn't find any other source to explain this. Am I asking too much from this attribute? or doing something else wrong?

Thanks in advance!

Upvotes: 1

Views: 1772

Answers (2)

Hal
Hal

Reputation: 1139

attribute(__aligned__())

is pretty horrible.I call it a bug. No traction at all on the gcc list. Not even acknowledgement that anybody read it.

https://gcc.gnu.org/ml/gcc/2014-06/msg00308.html

note that you can't even check that what you got was aligned because it will calculate the maths incorrectly.

0xxxxxx30 % 0x40 == 0x0 //really? that's aligned to 64b?

posix_memalign() or bust

Upvotes: 0

rici
rici

Reputation: 241911

You're using gcc's C extension to define your alignment. That will affect the size of the object (which needs to be a multiple of the alignment) and might affect the storage layout of objects with static alignment, but only to the extent to which the linker is prepared to align such objects. It does not affect the alignment of dynamically allocate objects, even in C++.

The C++ new operator calls an allocator function to provide storage, and then proceeds to initialize the storage by invoking the object constructor. The standard requires the allocation function to return a pointer "suitably aligned so that it can be converted to a pointer of any complete object type with a fundamental alignment requirement." (§3.7.4.1p2). The default standard library global allocator must conform to this requirement (§18.6.1). The definition of "fundamental alignment requirement" is implementation-specific, but it must be at least as large as the alignment requirement of any scalar type, and does not need to be any larger.

The global allocation function, as specified by the C++ standard, has only a single parameter, which is the size of the requested object. It is not passed any information about the alignment of the object, or the type, so it cannot perform an alignment-specific allocation.

You're free to define an allocation function for a given type, which can take that type's alignment into account. However, it would have to either use a non-standard (i.e. system-specific) underlying allocator, or over-allocate and then adjust the pointer. (C++11 provides a standard-library function align for this purpose.)

As I read the standard, C++11 requires the new expression to fail if the alignment of the object type exceeds the capability of the underlying allocator:

§3.11p9 If a request for a specific extended alignment in a specific context is not supported by an implementation, the program is ill-formed. Additionally, a request for runtime allocation of dynamic storage for which the requested alignment cannot be honored shall be treated as an allocation failure.

That won't apply to your program, since you are using a GCC-specific C-oriented alignment attribute, and certainly not C++11, so I suppose the compiler is within its rights to call an allocator which will return insufficiently aligned storage rather than throwing bad_alloc.

By the way, gcc 4.2.2 just celebrated its sixth birthday. You should consider sending it off to grade school and updating to something more modern.

Upvotes: 4

Related Questions