• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * This file has no copyright assigned and is placed in the Public Domain.
3  * This file is part of the mingw-w64 runtime package.
4  * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5  */
6 /*
7   __mingw_aligned_malloc and friends, implemented using Microsoft's public
8   interfaces and with the help of the algorithm description provided
9   by Wu Yongwei: http://sourceforge.net/mailarchive/message.php?msg_id=3847075
10 
11   I hereby place this implementation in the public domain.
12                -- Steven G. Johnson (stevenj@alum.mit.edu)
13 */
14 
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <stddef.h>		/* ptrdiff_t */
18 #include <stdint.h>		/* uintptr_t */
19 #include <string.h>		/* memmove */
20 
21 /* Forward declarations:  */
22 void *__mingw_aligned_offset_malloc (size_t, size_t, size_t);
23 
24 #define NOT_POWER_OF_TWO(n) (((n) & ((n) - 1)))
25 #define UI(p) ((uintptr_t) (p))
26 #define CP(p) ((char *) p)
27 
28 #define PTR_ALIGN(p0, alignment, offset)				\
29             ((void *) (((UI(p0) + (alignment + sizeof(void*)) + offset)	\
30 			& (~UI(alignment - 1)))				\
31 		       - offset))
32 
33 /* Pointer must sometimes be aligned; assume sizeof(void*) is a power of two. */
34 #define ORIG_PTR(p) (*(((void **) (UI(p) & (~UI(sizeof(void*) - 1)))) - 1))
35 
36 void *
__mingw_aligned_offset_malloc(size_t size,size_t alignment,size_t offset)37 __mingw_aligned_offset_malloc (size_t size, size_t alignment, size_t offset)
38 {
39   void *p0, *p;
40 
41   if (NOT_POWER_OF_TWO (alignment))
42     {
43       errno = EINVAL;
44       return ((void *) 0);
45     }
46   if (size == 0)
47     return ((void *) 0);
48   if (alignment < sizeof (void *))
49     alignment = sizeof (void *);
50 
51   /* Including the extra sizeof(void*) is overkill on a 32-bit
52      machine, since malloc is already 8-byte aligned, as long
53      as we enforce alignment >= 8 ...but oh well.  */
54 
55   p0 = malloc (size + (alignment + sizeof (void *)));
56   if (!p0)
57     return ((void *) 0);
58   p = PTR_ALIGN (p0, alignment, offset);
59   ORIG_PTR (p) = p0;
60   return p;
61 }
62 
63 void *
__mingw_aligned_malloc(size_t size,size_t alignment)64 __mingw_aligned_malloc (size_t size, size_t alignment)
65 {
66   return __mingw_aligned_offset_malloc (size, alignment, 0);
67 }
68 
69 void
__mingw_aligned_free(void * memblock)70 __mingw_aligned_free (void *memblock)
71 {
72   if (memblock)
73     free (ORIG_PTR (memblock));
74 }
75 
76 void *
__mingw_aligned_offset_realloc(void * memblock,size_t size,size_t alignment,size_t offset)77 __mingw_aligned_offset_realloc (void *memblock, size_t size,
78 				size_t alignment, size_t offset)
79 {
80   void *p0, *p;
81   ptrdiff_t shift;
82 
83   if (!memblock)
84     return __mingw_aligned_offset_malloc (size, alignment, offset);
85   if (NOT_POWER_OF_TWO (alignment))
86     goto bad;
87   if (size == 0)
88     {
89       __mingw_aligned_free (memblock);
90       return ((void *) 0);
91     }
92   if (alignment < sizeof (void *))
93     alignment = sizeof (void *);
94 
95   p0 = ORIG_PTR (memblock);
96   /* It is an error for the alignment to change. */
97   if (memblock != PTR_ALIGN (p0, alignment, offset))
98     goto bad;
99   shift = CP (memblock) - CP (p0);
100 
101   p0 = realloc (p0, size + (alignment + sizeof (void *)));
102   if (!p0)
103     return ((void *) 0);
104   p = PTR_ALIGN (p0, alignment, offset);
105 
106   /* Relative shift of actual data may be different from before, ugh.  */
107   if (shift != CP (p) - CP (p0))
108     /* ugh, moves more than necessary if size is increased.  */
109     memmove (CP (p), CP (p0) + shift, size);
110 
111   ORIG_PTR (p) = p0;
112   return p;
113 
114 bad:
115   errno = EINVAL;
116   return ((void *) 0);
117 }
118 
119 void *
__mingw_aligned_realloc(void * memblock,size_t size,size_t alignment)120 __mingw_aligned_realloc (void *memblock, size_t size, size_t alignment)
121 {
122   return __mingw_aligned_offset_realloc (memblock, size, alignment, 0);
123 }
124