Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to guarantee alignment of members of a malloc()-ed structs

I recently fixed a bug in which a __declspec(align(64)) member of a struct was misaligned because of the way the memory for the struct was allocated. So, I'm looking a way to work around such situations.

For example, consider the following struct:

struct foo {
    __declspec(align(64)) int bar[BAZ_LEN];
    int baz;
};

If allocated on the stack, the compiler would take care of the alignment. If allocated via malloc(), it would not work. This will break the code that accesses bar if it depends on its alignment for performance or correctness reasons (or both).

So, the question is: what is the best way to handle such situations? In my situation struct foo can be considered opaque for all but 'private' functions of my component.

Clarification/update. Thanks so much for the answers. I should have said this beforehand, but the problem was that the user of my struct allocated a chunk of memory and sliced it into multiple pieces, and one of the middle ones was an array of foo_t structus. The offset to that array is not constant, so aligning the starting address is not likely to help. I'm looking for a way to allow such usage of my structs while retaining some of the alignment assumptions.

The solution I have in mind right now (have not tried this) is to add a padding member:

struct foo {
    __declspec(align(64)) int bar[BAZ_LEN];
    int baz;
    char padding[64];
};

And than in every function do the following (wrapped in a macro):

void f(foo_t *foo_)
{
    foo_t *foo = (foo_t *)(((uintptr_t)foo_ & ~63) + 64);
    ...
}

This wastes 64 bytes per struct which is not an issue in my case. Since the padding member is never accessed the shift would not cause any segfaults. However this solution adds quite a bit of mental overhead since the alignment has to be sanitized for each public function...

like image 290
kolbusa Avatar asked Dec 31 '13 15:12

kolbusa


People also ask

Does malloc guarantee alignment?

The only standard rule is that the address returned by malloc will be suitably aligned to store any kind of variable. What exactly that means is platform-specific (since alignment requirements vary from platform to platform).

Why is malloc aligned?

malloc has no knowledge of what it is allocating for because its parameter is just total size. It just aligns to an alignment that is safe for any object.

Is malloc 16 byte aligned?

The GNU documentation states that malloc is aligned to 16 byte multiples on 64 bit systems.

What is bit alignment?

Alignment refers to the arrangement of data in memory, and specifically deals with the issue of accessing data as proper units of information from main memory. First we must conceptualize main memory as a contiguous block of consecutive memory locations. Each location contains a fixed number of bits.


1 Answers

In standard C11, you can use aligned_alloc():

ISO/IEC 9899:2011

7.22.3.1 The aligned_alloc function

Synopsis

#include <stdlib.h>  
void *aligned_alloc(size_t alignment, size_t size);

Description
2 The aligned_alloc function allocates space for an object whose alignment is specified by alignment, whose size is specified by size, and whose value is indeterminate. The value of alignment shall be a valid alignment supported by the implementation and the value of size shall be an integral multiple of alignment.

Returns
3 The aligned_alloc function returns either a null pointer or a pointer to the allocated space.

Or you can use POSIX posix_memalign():

NAME

posix_memalign — aligned memory allocation (ADVANCED REALTIME)

SYNOPSIS

#include <stdlib.h>  
int posix_memalign(void **memptr, size_t alignment, size_t size); [Option End]

DESCRIPTION

The posix_memalign() function shall allocate size bytes aligned on a boundary specified by alignment, and shall return a pointer to the allocated memory in memptr. The value of alignment shall be a power of two multiple of sizeof(void *).

Upon successful completion, the value pointed to by memptr shall be a multiple of alignment.

If the size of the space requested is 0, the behavior is implementation-defined; the value returned in memptr shall be either a null pointer or a unique pointer.

The free() function shall deallocate memory that has previously been allocated by posix_memalign().

RETURN VALUE

Upon successful completion, posix_memalign() shall return zero; otherwise, an error number shall be returned to indicate the error.

Note that there is no aligned_realloc() nor a POSIX equivalent.

like image 67
Jonathan Leffler Avatar answered Sep 23 '22 18:09

Jonathan Leffler