1 /*
2  * Copyright 2013 MongoDB, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include "bson-atomic.h"
22 #include "bson-config.h"
23 #include "bson-memory.h"
24 
25 
26 static bson_mem_vtable_t gMemVtable = {
27    malloc,
28    calloc,
29 #ifdef BSON_HAVE_REALLOCF
30    reallocf,
31 #else
32    realloc,
33 #endif
34    free,
35 };
36 
37 
38 /*
39  *--------------------------------------------------------------------------
40  *
41  * bson_malloc --
42  *
43  *       Allocates @num_bytes of memory and returns a pointer to it.  If
44  *       malloc failed to allocate the memory, abort() is called.
45  *
46  *       Libbson does not try to handle OOM conditions as it is beyond the
47  *       scope of this library to handle so appropriately.
48  *
49  * Parameters:
50  *       @num_bytes: The number of bytes to allocate.
51  *
52  * Returns:
53  *       A pointer if successful; otherwise abort() is called and this
54  *       function will never return.
55  *
56  * Side effects:
57  *       None.
58  *
59  *--------------------------------------------------------------------------
60  */
61 
62 void *
bson_malloc(size_t num_bytes)63 bson_malloc (size_t num_bytes) /* IN */
64 {
65    void *mem = NULL;
66 
67    if (BSON_LIKELY (num_bytes)) {
68       if (BSON_UNLIKELY (!(mem = gMemVtable.malloc (num_bytes)))) {
69          abort ();
70       }
71    }
72 
73    return mem;
74 }
75 
76 
77 /*
78  *--------------------------------------------------------------------------
79  *
80  * bson_malloc0 --
81  *
82  *       Like bson_malloc() except the memory is zeroed first. This is
83  *       similar to calloc() except that abort() is called in case of
84  *       failure to allocate memory.
85  *
86  * Parameters:
87  *       @num_bytes: The number of bytes to allocate.
88  *
89  * Returns:
90  *       A pointer if successful; otherwise abort() is called and this
91  *       function will never return.
92  *
93  * Side effects:
94  *       None.
95  *
96  *--------------------------------------------------------------------------
97  */
98 
99 void *
bson_malloc0(size_t num_bytes)100 bson_malloc0 (size_t num_bytes) /* IN */
101 {
102    void *mem = NULL;
103 
104    if (BSON_LIKELY (num_bytes)) {
105       if (BSON_UNLIKELY (!(mem = gMemVtable.calloc (1, num_bytes)))) {
106          abort ();
107       }
108    }
109 
110    return mem;
111 }
112 
113 
114 /*
115  *--------------------------------------------------------------------------
116  *
117  * bson_realloc --
118  *
119  *       This function behaves similar to realloc() except that if there is
120  *       a failure abort() is called.
121  *
122  * Parameters:
123  *       @mem: The memory to realloc, or NULL.
124  *       @num_bytes: The size of the new allocation or 0 to free.
125  *
126  * Returns:
127  *       The new allocation if successful; otherwise abort() is called and
128  *       this function never returns.
129  *
130  * Side effects:
131  *       None.
132  *
133  *--------------------------------------------------------------------------
134  */
135 
136 void *
bson_realloc(void * mem,size_t num_bytes)137 bson_realloc (void *mem,        /* IN */
138               size_t num_bytes) /* IN */
139 {
140    /*
141     * Not all platforms are guaranteed to free() the memory if a call to
142     * realloc() with a size of zero occurs. Windows, Linux, and FreeBSD do,
143     * however, OS X does not.
144     */
145    if (BSON_UNLIKELY (num_bytes == 0)) {
146       gMemVtable.free (mem);
147       return NULL;
148    }
149 
150    mem = gMemVtable.realloc (mem, num_bytes);
151 
152    if (BSON_UNLIKELY (!mem)) {
153       abort ();
154    }
155 
156    return mem;
157 }
158 
159 
160 /*
161  *--------------------------------------------------------------------------
162  *
163  * bson_realloc_ctx --
164  *
165  *       This wraps bson_realloc and provides a compatible api for similar
166  *       functions with a context
167  *
168  * Parameters:
169  *       @mem: The memory to realloc, or NULL.
170  *       @num_bytes: The size of the new allocation or 0 to free.
171  *       @ctx: Ignored
172  *
173  * Returns:
174  *       The new allocation if successful; otherwise abort() is called and
175  *       this function never returns.
176  *
177  * Side effects:
178  *       None.
179  *
180  *--------------------------------------------------------------------------
181  */
182 
183 
184 void *
bson_realloc_ctx(void * mem,size_t num_bytes,void * ctx)185 bson_realloc_ctx (void *mem,        /* IN */
186                   size_t num_bytes, /* IN */
187                   void *ctx)        /* IN */
188 {
189    return bson_realloc (mem, num_bytes);
190 }
191 
192 
193 /*
194  *--------------------------------------------------------------------------
195  *
196  * bson_free --
197  *
198  *       Frees @mem using the underlying allocator.
199  *
200  *       Currently, this only calls free() directly, but that is subject to
201  *       change.
202  *
203  * Parameters:
204  *       @mem: An allocation to free.
205  *
206  * Returns:
207  *       None.
208  *
209  * Side effects:
210  *       None.
211  *
212  *--------------------------------------------------------------------------
213  */
214 
215 void
bson_free(void * mem)216 bson_free (void *mem) /* IN */
217 {
218    gMemVtable.free (mem);
219 }
220 
221 
222 /*
223  *--------------------------------------------------------------------------
224  *
225  * bson_zero_free --
226  *
227  *       Frees @mem using the underlying allocator. @size bytes of @mem will
228  *       be zeroed before freeing the memory. This is useful in scenarios
229  *       where @mem contains passwords or other sensitive information.
230  *
231  * Parameters:
232  *       @mem: An allocation to free.
233  *       @size: The number of bytes in @mem.
234  *
235  * Returns:
236  *       None.
237  *
238  * Side effects:
239  *       None.
240  *
241  *--------------------------------------------------------------------------
242  */
243 
244 void
bson_zero_free(void * mem,size_t size)245 bson_zero_free (void *mem,   /* IN */
246                 size_t size) /* IN */
247 {
248    if (BSON_LIKELY (mem)) {
249       memset (mem, 0, size);
250       gMemVtable.free (mem);
251    }
252 }
253 
254 
255 /*
256  *--------------------------------------------------------------------------
257  *
258  * bson_mem_set_vtable --
259  *
260  *       This function will change our allocationt vtable.
261  *
262  *       It is imperitive that this is called at the beginning of the
263  *       process before any memory has been allocated by the default
264  *       allocator.
265  *
266  * Returns:
267  *       None.
268  *
269  * Side effects:
270  *       None.
271  *
272  *--------------------------------------------------------------------------
273  */
274 
275 void
bson_mem_set_vtable(const bson_mem_vtable_t * vtable)276 bson_mem_set_vtable (const bson_mem_vtable_t *vtable)
277 {
278    BSON_ASSERT (vtable);
279 
280    if (!vtable->malloc || !vtable->calloc || !vtable->realloc ||
281        !vtable->free) {
282       fprintf (stderr,
283                "Failure to install BSON vtable, "
284                "missing functions.\n");
285       return;
286    }
287 
288    gMemVtable = *vtable;
289 }
290 
291 void
bson_mem_restore_vtable(void)292 bson_mem_restore_vtable (void)
293 {
294    bson_mem_vtable_t vtable = {
295       malloc,
296       calloc,
297 #ifdef BSON_HAVE_REALLOCF
298       reallocf,
299 #else
300       realloc,
301 #endif
302       free,
303    };
304 
305    bson_mem_set_vtable (&vtable);
306 }
307