|  | /** | 
|  | * This file has no copyright assigned and is placed in the Public Domain. | 
|  | * This file is part of the mingw-w64 runtime package. | 
|  | * No warranty is given; refer to the file DISCLAIMER.PD within this package. | 
|  | */ | 
|  | /* | 
|  | __mingw_aligned_malloc and friends, implemented using Microsoft's public | 
|  | interfaces and with the help of the algorithm description provided | 
|  | by Wu Yongwei: http://sourceforge.net/mailarchive/message.php?msg_id=3847075 | 
|  |  | 
|  | I hereby place this implementation in the public domain. | 
|  | -- Steven G. Johnson (stevenj@alum.mit.edu) | 
|  | */ | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <errno.h> | 
|  | #include <stddef.h>		/* ptrdiff_t */ | 
|  | #include <stdint.h>		/* uintptr_t */ | 
|  | #include <string.h>		/* memmove */ | 
|  |  | 
|  | /* Forward declarations:  */ | 
|  | void *__mingw_aligned_offset_malloc (size_t, size_t, size_t); | 
|  |  | 
|  | #define NOT_POWER_OF_TWO(n) (((n) & ((n) - 1))) | 
|  | #define UI(p) ((uintptr_t) (p)) | 
|  | #define CP(p) ((char *) p) | 
|  |  | 
|  | #define PTR_ALIGN(p0, alignment, offset)				\ | 
|  | ((void *) (((UI(p0) + (alignment + sizeof(void*)) + offset)	\ | 
|  | & (~UI(alignment - 1)))				\ | 
|  | - offset)) | 
|  |  | 
|  | /* Pointer must sometimes be aligned; assume sizeof(void*) is a power of two. */ | 
|  | #define ORIG_PTR(p) (*(((void **) (UI(p) & (~UI(sizeof(void*) - 1)))) - 1)) | 
|  |  | 
|  | void * | 
|  | __mingw_aligned_offset_malloc (size_t size, size_t alignment, size_t offset) | 
|  | { | 
|  | void *p0, *p; | 
|  |  | 
|  | if (NOT_POWER_OF_TWO (alignment)) | 
|  | { | 
|  | errno = EINVAL; | 
|  | return ((void *) 0); | 
|  | } | 
|  | if (size == 0) | 
|  | return ((void *) 0); | 
|  | if (alignment < sizeof (void *)) | 
|  | alignment = sizeof (void *); | 
|  |  | 
|  | /* Including the extra sizeof(void*) is overkill on a 32-bit | 
|  | machine, since malloc is already 8-byte aligned, as long | 
|  | as we enforce alignment >= 8 ...but oh well.  */ | 
|  |  | 
|  | p0 = malloc (size + (alignment + sizeof (void *))); | 
|  | if (!p0) | 
|  | return ((void *) 0); | 
|  | p = PTR_ALIGN (p0, alignment, offset); | 
|  | ORIG_PTR (p) = p0; | 
|  | return p; | 
|  | } | 
|  |  | 
|  | void * | 
|  | __mingw_aligned_malloc (size_t size, size_t alignment) | 
|  | { | 
|  | return __mingw_aligned_offset_malloc (size, alignment, 0); | 
|  | } | 
|  |  | 
|  | void | 
|  | __mingw_aligned_free (void *memblock) | 
|  | { | 
|  | if (memblock) | 
|  | free (ORIG_PTR (memblock)); | 
|  | } | 
|  |  | 
|  | void * | 
|  | __mingw_aligned_offset_realloc (void *memblock, size_t size, | 
|  | size_t alignment, size_t offset) | 
|  | { | 
|  | void *p0, *p; | 
|  | ptrdiff_t shift; | 
|  |  | 
|  | if (!memblock) | 
|  | return __mingw_aligned_offset_malloc (size, alignment, offset); | 
|  | if (NOT_POWER_OF_TWO (alignment)) | 
|  | goto bad; | 
|  | if (size == 0) | 
|  | { | 
|  | __mingw_aligned_free (memblock); | 
|  | return ((void *) 0); | 
|  | } | 
|  | if (alignment < sizeof (void *)) | 
|  | alignment = sizeof (void *); | 
|  |  | 
|  | p0 = ORIG_PTR (memblock); | 
|  | /* It is an error for the alignment to change. */ | 
|  | if (memblock != PTR_ALIGN (p0, alignment, offset)) | 
|  | goto bad; | 
|  | shift = CP (memblock) - CP (p0); | 
|  |  | 
|  | p0 = realloc (p0, size + (alignment + sizeof (void *))); | 
|  | if (!p0) | 
|  | return ((void *) 0); | 
|  | p = PTR_ALIGN (p0, alignment, offset); | 
|  |  | 
|  | /* Relative shift of actual data may be different from before, ugh.  */ | 
|  | if (shift != CP (p) - CP (p0)) | 
|  | /* ugh, moves more than necessary if size is increased.  */ | 
|  | memmove (CP (p), CP (p0) + shift, size); | 
|  |  | 
|  | ORIG_PTR (p) = p0; | 
|  | return p; | 
|  |  | 
|  | bad: | 
|  | errno = EINVAL; | 
|  | return ((void *) 0); | 
|  | } | 
|  |  | 
|  | void * | 
|  | __mingw_aligned_realloc (void *memblock, size_t size, size_t alignment) | 
|  | { | 
|  | return __mingw_aligned_offset_realloc (memblock, size, alignment, 0); | 
|  | } |