master
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#define NOT_POWER_OF_TWO(n) (((n) & ((n) - 1)))
22#define UI(p) ((uintptr_t) (p))
23#define CP(p) ((char *) p)
24
25#define GAP(offset) ((0 - offset) & (sizeof (void *) -1))
26#define PTR_ALIGN(p0, alignment, offset) \
27 ((void *) (((UI(p0) + (alignment + GAP(offset) + sizeof(void*)) + offset) \
28 & (~UI(alignment))) \
29 - offset))
30
31/* Pointer must sometimes be aligned; assume sizeof(void*) is a power of two. */
32#define ORIG_PTR(p) (*(((void **) (UI(p) & (~UI(sizeof(void*) - 1)))) - 1))
33
34void *
35__mingw_aligned_offset_malloc (size_t size, size_t alignment, size_t offset)
36{
37 void *p0, *p;
38
39 if (NOT_POWER_OF_TWO (alignment))
40 {
41 errno = EINVAL;
42 return ((void *) 0);
43 }
44 if (size == 0)
45 return ((void *) 0);
46 if (alignment < sizeof (void *))
47 alignment = sizeof (void *);
48 alignment--;
49
50 /* Including the extra sizeof(void*) is overkill on a 32-bit
51 machine, since malloc is already 8-byte aligned, as long
52 as we enforce alignment >= 8 ...but oh well. */
53
54 p0 = malloc (size + (alignment + GAP (offset) + sizeof (void *)));
55 if (!p0)
56 return ((void *) 0);
57 p = PTR_ALIGN (p0, alignment, offset);
58 ORIG_PTR (p) = p0;
59 return p;
60}
61
62void *
63__mingw_aligned_malloc (size_t size, size_t alignment)
64{
65 return __mingw_aligned_offset_malloc (size, alignment, 0);
66}
67
68void
69__mingw_aligned_free (void *memblock)
70{
71 if (memblock)
72 free (ORIG_PTR (memblock));
73}
74
75void *
76__mingw_aligned_offset_realloc (void *memblock, size_t size,
77 size_t alignment, size_t offset)
78{
79 void *p0, *p;
80 ptrdiff_t shift;
81
82 if (!memblock)
83 return __mingw_aligned_offset_malloc (size, alignment, offset);
84 if (NOT_POWER_OF_TWO (alignment))
85 goto bad;
86 if (size == 0)
87 {
88 __mingw_aligned_free (memblock);
89 return ((void *) 0);
90 }
91 if (alignment < sizeof (void *))
92 alignment = sizeof (void *);
93 alignment--;
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 + GAP (offset) + 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
114bad:
115 errno = EINVAL;
116 return ((void *) 0);
117}
118
119void *
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
125size_t
126__mingw_aligned_msize (void *memblock, size_t alignment, size_t offset)
127{
128 void *p0;
129
130 if (!memblock || NOT_POWER_OF_TWO (alignment))
131 {
132 errno = EINVAL;
133 return (size_t)-1;
134 }
135 if (alignment < sizeof (void *))
136 alignment = sizeof (void *);
137 alignment--;
138
139 p0 = ORIG_PTR (memblock);
140
141 /* It is an error if the alignment or offset does not match. */
142 if (memblock != PTR_ALIGN (p0, alignment, offset))
143 {
144 errno = EINVAL;
145 return (size_t)-1;
146 }
147
148 return _msize (p0) - (alignment + GAP (offset) + sizeof (void *));
149}