OSDN Git Service

8d3b555ca725d6e67f45446b9347f45aacff5923
[mingw/mingw-org-wsl.git] / src / libcrt / misc / mingw-aligned-malloc.c
1 /**
2  * @file mingw-aligned-malloc.c
3  * @copy 2012 MinGW.org project
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  * 
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  * 
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <stddef.h>             /* ptrdiff_t */
27 #include <string.h>             /* memmove */
28
29 #ifdef HAVE_STDINT_H
30 #  include <stdint.h>           /* uintptr_t */
31 #else
32 #  define uintptr_t size_t
33 #endif
34
35 #define NOT_POWER_OF_TWO(n) (((n) & ((n) - 1)))
36 #define UI(p) ((uintptr_t) (p))
37 #define CP(p) ((char *) p)
38
39 #define PTR_ALIGN(p0, alignment, offset)                                \
40             ((void *) (((UI(p0) + (alignment + sizeof(void*)) + offset) \
41                         & (~UI(alignment - 1)))                         \
42                        - offset))
43
44 /* Pointer must sometimes be aligned; assume sizeof(void*) is a power of two. */
45 #define ORIG_PTR(p) (*(((void **) (UI(p) & (~UI(sizeof(void*) - 1)))) - 1))
46
47 void *
48 __mingw_aligned_offset_malloc (size_t size, size_t alignment, size_t offset)
49 {
50   void *p0, *p;
51
52   if (NOT_POWER_OF_TWO (alignment))
53     {
54       errno = EINVAL;
55       return ((void *) 0);
56     }
57   if (size == 0)
58     return ((void *) 0);
59   if (alignment < sizeof (void *))
60     alignment = sizeof (void *);
61
62   /* Including the extra sizeof(void*) is overkill on a 32-bit
63      machine, since malloc is already 8-byte aligned, as long
64      as we enforce alignment >= 8 ...but oh well.  */
65
66   p0 = malloc (size + (alignment + sizeof (void *)));
67   if (!p0)
68     return ((void *) 0);
69   p = PTR_ALIGN (p0, alignment, offset);
70   ORIG_PTR (p) = p0;
71   return p;
72 }
73
74 void *
75 __mingw_aligned_malloc (size_t size, size_t alignment)
76 {
77   return __mingw_aligned_offset_malloc (size, alignment, 0);
78 }
79
80 void
81 __mingw_aligned_free (void *memblock)
82 {
83   if (memblock)
84     free (ORIG_PTR (memblock));
85 }
86
87 void *
88 __mingw_aligned_offset_realloc (void *memblock, size_t size,
89                                 size_t alignment, size_t offset)
90 {
91   void *p0, *p;
92   ptrdiff_t shift;
93
94   if (!memblock)
95     return __mingw_aligned_offset_malloc (size, alignment, offset);
96   if (NOT_POWER_OF_TWO (alignment))
97     goto bad;
98   if (size == 0)
99     {
100       __mingw_aligned_free (memblock);
101       return ((void *) 0);
102     }
103   if (alignment < sizeof (void *))
104     alignment = sizeof (void *);
105
106   p0 = ORIG_PTR (memblock);
107   /* It is an error for the alignment to change. */
108   if (memblock != PTR_ALIGN (p0, alignment, offset))
109     goto bad;
110   shift = CP (memblock) - CP (p0);
111
112   p0 = realloc (p0, size + (alignment + sizeof (void *)));
113   if (!p0)
114     return ((void *) 0);
115   p = PTR_ALIGN (p0, alignment, offset);
116
117   /* Relative shift of actual data may be different from before, ugh.  */
118   if (shift != CP (p) - CP (p0))
119     /* ugh, moves more than necessary if size is increased.  */
120     memmove (CP (p), CP (p0) + shift, size);
121
122   ORIG_PTR (p) = p0;
123   return p;
124
125 bad:
126   errno = EINVAL;
127   return ((void *) 0);
128 }
129
130 void *
131 __mingw_aligned_realloc (void *memblock, size_t size, size_t alignment)
132 {
133   return __mingw_aligned_offset_realloc (memblock, size, alignment, 0);
134 }