1/* graphene-alloc.c: aligned allocator
2 *
3 * SPDX-License-Identifier: MIT
4 *
5 * Copyright 2014 Emmanuele Bassi
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26#include "graphene-private.h"
27#include "graphene-alloc-private.h"
28
29#if defined(HAVE_POSIX_MEMALIGN) && !defined(_XOPEN_SOURCE)
30# define _XOPEN_SOURCE 600
31#endif
32
33#if defined(HAVE_MEMALIGN) || defined(HAVE__ALIGNED_MALLOC)
34/* Required for _aligned_malloc() and _aligned_free() on Windows */
35#include <malloc.h>
36#endif
37
38#ifdef HAVE__ALIGNED_MALLOC
39/* _aligned_malloc() takes parameters of aligned_malloc() in reverse order */
40# define aligned_alloc(alignment, size) _aligned_malloc (size, alignment)
41
42/* _aligned_malloc()'ed memory must be freed by _align_free() on MSVC */
43# define aligned_free(x) _aligned_free (x)
44#else
45# define aligned_free(x) free (x)
46#endif
47
48#include <string.h>
49#include <stdlib.h>
50#include <stdio.h>
51#include <errno.h>
52
53/*< private >
54 * graphene_aligned_alloc:
55 * @size: the size of the memory to allocate
56 * @number: the multiples of @size to allocate
57 * @alignment: the alignment to be enforced, as a power of 2
58 *
59 * Allocates @number times @size memory, with the given @alignment.
60 *
61 * If the total requested memory overflows %G_MAXSIZE, this function
62 * will abort.
63 *
64 * If allocation fails, this function will abort, in line with
65 * the behaviour of GLib.
66 *
67 * Returns: (transfer full): the allocated memory
68 */
69void *
70graphene_aligned_alloc (size_t size,
71 size_t number,
72 size_t alignment)
73{
74 void *res = NULL;
75 size_t max_size = (size_t) -1;
76 size_t real_size;
77
78 if (size == 0 || number == 0)
79 return NULL;
80
81 if (size > 0 && number > max_size / size)
82 {
83#ifndef G_DISABLE_ASSERT
84 fprintf (stderr,
85 format: "Overflow in the allocation of (%lu x %lu) bytes\n",
86 (unsigned long) size,
87 (unsigned long) number);
88 abort ();
89#else
90 return NULL;
91#endif
92 }
93
94 real_size = size * number;
95
96#ifndef G_DISABLE_ASSERT
97 errno = 0;
98#endif
99
100#if defined(HAVE_POSIX_MEMALIGN)
101 errno = posix_memalign (&res, alignment, real_size);
102#elif defined(HAVE_ALIGNED_ALLOC) || defined(HAVE__ALIGNED_MALLOC)
103 /* real_size must be a multiple of alignment */
104 if (real_size % alignment != 0)
105 {
106 size_t offset = real_size % alignment;
107 real_size += (alignment - offset);
108 }
109
110 res = aligned_alloc (alignment, real_size);
111#elif defined(HAVE_MEMALIGN)
112 res = memalign (alignment: alignment, size: real_size);
113#else
114 res = malloc (real_size);
115#endif
116
117#ifndef G_DISABLE_ASSERT
118 if (errno != 0 || res == NULL)
119 {
120 fprintf (stderr, format: "Allocation error: %s\n", strerror (errno));
121 abort ();
122 }
123#endif
124
125 return res;
126}
127
128/*< private >
129 * graphene_aligned_alloc:
130 * @size: the size of the memory to allocate
131 * @number: the multiples of @size to allocate
132 * @alignment: the alignment to be enforced, as a power of 2
133 *
134 * Allocates @number times @size memory, with the given @alignment,
135 * like graphene_aligned_alloc(), but it also clears the memory.
136 *
137 * Returns: (transfer full): the allocated, cleared memory
138 */
139void *
140graphene_aligned_alloc0 (size_t size,
141 size_t number,
142 size_t alignment)
143{
144 void *res = graphene_aligned_alloc (size, number, alignment);
145
146 if (res != NULL)
147 memset (s: res, c: 0, n: size * number);
148
149 return res;
150}
151
152/*< private >
153 * graphene_aligned_free:
154 * @mem: the memory to deallocate
155 *
156 * Frees the memory allocated by graphene_aligned_alloc().
157 */
158void
159graphene_aligned_free (void *mem)
160{
161 aligned_free (mem);
162}
163

source code of gtk/subprojects/graphene/src/graphene-alloc.c