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