1 /*
2 * libmowgli: A collection of useful routines for programming.
3 * alloc.c: Safe, portable implementations of malloc, calloc, and free.
4 *
5 * Copyright (c) 2007, 2012 William Pitcock <nenolod@dereferenced.org>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice is present in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
15 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
19 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
20 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21 * POSSIBILITY OF SUCH DAMAGE.
22 */
23
24 #include "mowgli.h"
25
26 /*
27 * bootstrapped allocators so that we can initialise without blowing up
28 */
29 typedef struct
30 {
31 mowgli_allocation_policy_t *allocator;
32 } alloc_tag_t;
33
34 static void *
_mowgli_bootstrap_alloc(size_t size)35 _mowgli_bootstrap_alloc(size_t size)
36 {
37 return calloc(size, 1);
38 }
39
40 static void
_mowgli_bootstrap_free(void * ptr)41 _mowgli_bootstrap_free(void *ptr)
42 {
43 if (ptr)
44 free(ptr);
45 }
46
47 static mowgli_allocation_policy_t _mowgli_allocator_bootstrap =
48 {
49 { 0 },
50 _mowgli_bootstrap_alloc,
51 _mowgli_bootstrap_free
52 };
53
54 static mowgli_allocation_policy_t *_mowgli_allocator = &_mowgli_allocator_bootstrap;
55
56 /*
57 * \brief Allocates an array of data that contains "count" objects,
58 * of "size" size.
59 *
60 * Usually, this wraps calloc().
61 *
62 * \param size size of objects to allocate.
63 * \param count amount of objects to allocate.
64 *
65 * \return A pointer to a memory buffer.
66 */
67 void *
mowgli_alloc_array_using_policy(mowgli_allocation_policy_t * policy,size_t size,size_t count)68 mowgli_alloc_array_using_policy(mowgli_allocation_policy_t *policy, size_t size, size_t count)
69 {
70 size_t adj_size;
71 void *r;
72
73 return_val_if_fail(policy != NULL, NULL);
74
75 adj_size = (size * count) + sizeof(alloc_tag_t);
76
77 r = policy->allocate(adj_size);
78 ((alloc_tag_t *) r)->allocator = policy;
79
80 return (char *) r + sizeof(alloc_tag_t);
81 }
82
83 /*
84 * \brief Allocates an object of "size" size.
85 *
86 * This is the equivilant of calling mowgli_alloc_array(size, 1).
87 *
88 * \param size size of object to allocate.
89 *
90 * \return A pointer to a memory buffer.
91 */
92 void *
mowgli_alloc_using_policy(mowgli_allocation_policy_t * policy,size_t size)93 mowgli_alloc_using_policy(mowgli_allocation_policy_t *policy, size_t size)
94 {
95 return mowgli_alloc_array_using_policy(policy, size, 1);
96 }
97
98 /*
99 * \brief Duplicater a string using mowgli_alloc() using a specific policy.
100 */
101 char *
mowgli_strdup_using_policy(mowgli_allocation_policy_t * policy,const char * in)102 mowgli_strdup_using_policy(mowgli_allocation_policy_t *policy, const char *in)
103 {
104 char *out;
105 size_t len;
106
107 return_val_if_fail(in != NULL, NULL);
108
109 len = strlen(in) + 1;
110 out = mowgli_alloc_using_policy(policy, len);
111 mowgli_strlcpy(out, in, len);
112
113 return out;
114 }
115
116 /*
117 * \brief Duplicater a string using mowgli_alloc() using a specific policy.
118 */
119 char *
mowgli_strdup(const char * in)120 mowgli_strdup(const char *in)
121 {
122 return mowgli_strdup_using_policy(_mowgli_allocator, in);
123 }
124
125 /*
126 * \brief Duplicate a string of a specified length using mowgli_alloc() using a specific policy.
127 */
128 char *
mowgli_strndup_using_policy(mowgli_allocation_policy_t * policy,const char * in,size_t size)129 mowgli_strndup_using_policy(mowgli_allocation_policy_t *policy, const char *in, size_t size)
130 {
131 char *out;
132 size_t len;
133
134 return_val_if_fail(in != NULL, NULL);
135
136 len = strlen(in) + 1;
137
138 if (size < len)
139 len = size;
140
141 out = mowgli_alloc_using_policy(policy, len);
142 mowgli_strlcpy(out, in, len);
143
144 return out;
145 }
146
147 /*
148 * \brief Duplicate a string of a specified length using mowgli_alloc() using a specific policy.
149 */
150 char *
mowgli_strndup(const char * in,size_t size)151 mowgli_strndup(const char *in, size_t size)
152 {
153 return mowgli_strndup_using_policy(_mowgli_allocator, in, size);
154 }
155
156 /*
157 * \brief Allocates an array of data that contains "count" objects,
158 * of "size" size.
159 *
160 * Usually, this wraps calloc().
161 *
162 * \param size size of objects to allocate.
163 * \param count amount of objects to allocate.
164 *
165 * \return A pointer to a memory buffer.
166 */
167 void *
mowgli_alloc_array(size_t size,size_t count)168 mowgli_alloc_array(size_t size, size_t count)
169 {
170 return mowgli_alloc_array_using_policy(_mowgli_allocator, size, count);
171 }
172
173 /*
174 * \brief Allocates an object of "size" size.
175 *
176 * This is the equivilant of calling mowgli_alloc_array(size, 1).
177 *
178 * \param size size of object to allocate.
179 *
180 * \return A pointer to a memory buffer.
181 */
182 void *
mowgli_alloc(size_t size)183 mowgli_alloc(size_t size)
184 {
185 return mowgli_alloc_array_using_policy(_mowgli_allocator, size, 1);
186 }
187
188 /*
189 * \brief Frees an object back to the system memory pool.
190 *
191 * Wraps free protecting against common mistakes (reports an error instead).
192 *
193 * \param ptr pointer to object to free.
194 */
195 void
mowgli_free(void * ptr)196 mowgli_free(void *ptr)
197 {
198 alloc_tag_t *tag;
199
200 return_if_fail(ptr != NULL);
201
202 tag = (alloc_tag_t *) ((char *) ptr - sizeof(alloc_tag_t));
203 tag->allocator->deallocate(tag);
204 }
205
206 /*
207 * \brief Sets the mowgli.allocation_policy used by the allocation primitives.
208 *
209 * \param policy The mowgli_allocation_policy_t object to use.
210 */
211 void
mowgli_allocator_set_policy(mowgli_allocation_policy_t * policy)212 mowgli_allocator_set_policy(mowgli_allocation_policy_t *policy)
213 {
214 return_if_fail(policy != NULL);
215
216 _mowgli_allocator = policy;
217 }
218
219 /*
220 * \brief Sets the mowgli.allocation_policy used by the allocation primitives,
221 * when given a name.
222 *
223 * \param name The name of the policy to use.
224 */
225 void
mowgli_allocator_set_policy_by_name(const char * name)226 mowgli_allocator_set_policy_by_name(const char *name)
227 {
228 mowgli_allocation_policy_t *policy;
229
230 return_if_fail(name != NULL);
231
232 policy = mowgli_allocation_policy_lookup(name);
233
234 if (policy == NULL)
235 return;
236
237 mowgli_allocator_set_policy(policy);
238 }
239