1 /*
2 * uriparser - RFC 3986 URI parsing library
3 *
4 * Copyright (C) 2018, Weijia Song <songweijia@gmail.com>
5 * Copyright (C) 2018, Sebastian Pipping <sebastian@pipping.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * 3. Neither the name of the copyright holder nor the names of
22 * its contributors may be used to endorse or promote products
23 * derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
30 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
31 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
37 * OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /**
41 * @file UriMemory.c
42 * Holds memory manager implementation.
43 */
44
45 #include <config.h>
46
47 #ifdef HAVE_REALLOCARRAY
48 # ifndef _GNU_SOURCE
49 # define _GNU_SOURCE 1
50 # endif
51 #endif
52
53 #include <errno.h>
54 #include <stdlib.h>
55
56
57
58 #ifndef URI_DOXYGEN
59 # include "UriMemory.h"
60 #endif
61
62
63
64 #define URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size) \
65 do { \
66 /* check for unsigned overflow */ \
67 if ((nmemb != 0) && (total_size / nmemb != size)) { \
68 errno = ENOMEM; \
69 return NULL; \
70 } \
71 } while (0)
72
73
74
uriDefaultMalloc(UriMemoryManager * URI_UNUSED (memory),size_t size)75 static void * uriDefaultMalloc(UriMemoryManager * URI_UNUSED(memory),
76 size_t size) {
77 return malloc(size);
78 }
79
80
81
uriDefaultCalloc(UriMemoryManager * URI_UNUSED (memory),size_t nmemb,size_t size)82 static void * uriDefaultCalloc(UriMemoryManager * URI_UNUSED(memory),
83 size_t nmemb, size_t size) {
84 return calloc(nmemb, size);
85 }
86
87
88
uriDefaultRealloc(UriMemoryManager * URI_UNUSED (memory),void * ptr,size_t size)89 static void * uriDefaultRealloc(UriMemoryManager * URI_UNUSED(memory),
90 void * ptr, size_t size) {
91 return realloc(ptr, size);
92 }
93
94
95
uriDefaultReallocarray(UriMemoryManager * URI_UNUSED (memory),void * ptr,size_t nmemb,size_t size)96 static void * uriDefaultReallocarray(UriMemoryManager * URI_UNUSED(memory),
97 void * ptr, size_t nmemb, size_t size) {
98 #ifdef HAVE_REALLOCARRAY
99 return reallocarray(ptr, nmemb, size);
100 #else
101 const size_t total_size = nmemb * size;
102
103 URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */
104
105 return realloc(ptr, total_size);
106 #endif
107 }
108
109
110
uriDefaultFree(UriMemoryManager * URI_UNUSED (memory),void * ptr)111 static void uriDefaultFree(UriMemoryManager * URI_UNUSED(memory),
112 void * ptr) {
113 free(ptr);
114 }
115
116
117
uriMemoryManagerIsComplete(const UriMemoryManager * memory)118 UriBool uriMemoryManagerIsComplete(const UriMemoryManager * memory) {
119 return (memory
120 && memory->malloc
121 && memory->calloc
122 && memory->realloc
123 && memory->reallocarray
124 && memory->free) ? URI_TRUE : URI_FALSE;
125 }
126
127
128
uriEmulateCalloc(UriMemoryManager * memory,size_t nmemb,size_t size)129 void * uriEmulateCalloc(UriMemoryManager * memory, size_t nmemb, size_t size) {
130 void * buffer;
131 const size_t total_size = nmemb * size;
132
133 if (memory == NULL) {
134 errno = EINVAL;
135 return NULL;
136 }
137
138 URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */
139
140 buffer = memory->malloc(memory, total_size);
141 if (buffer == NULL) {
142 /* errno set by malloc */
143 return NULL;
144 }
145 memset(buffer, 0, total_size);
146 return buffer;
147 }
148
149
150
uriEmulateReallocarray(UriMemoryManager * memory,void * ptr,size_t nmemb,size_t size)151 void * uriEmulateReallocarray(UriMemoryManager * memory,
152 void * ptr, size_t nmemb, size_t size) {
153 const size_t total_size = nmemb * size;
154
155 if (memory == NULL) {
156 errno = EINVAL;
157 return NULL;
158 }
159
160 URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */
161
162 return memory->realloc(memory, ptr, total_size);
163 }
164
165
166
uriDecorateMalloc(UriMemoryManager * memory,size_t size)167 static void * uriDecorateMalloc(UriMemoryManager * memory,
168 size_t size) {
169 UriMemoryManager * backend;
170 const size_t extraBytes = sizeof(size_t);
171 void * buffer;
172
173 if (memory == NULL) {
174 errno = EINVAL;
175 return NULL;
176 }
177
178 /* check for unsigned overflow */
179 if (size > ((size_t)-1) - extraBytes) {
180 errno = ENOMEM;
181 return NULL;
182 }
183
184 backend = (UriMemoryManager *)memory->userData;
185 if (backend == NULL) {
186 errno = EINVAL;
187 return NULL;
188 }
189
190 buffer = backend->malloc(backend, extraBytes + size);
191 if (buffer == NULL) {
192 return NULL;
193 }
194
195 *(size_t *)buffer = size;
196
197 return (char *)buffer + extraBytes;
198 }
199
200
201
uriDecorateRealloc(UriMemoryManager * memory,void * ptr,size_t size)202 static void * uriDecorateRealloc(UriMemoryManager * memory,
203 void * ptr, size_t size) {
204 void * newBuffer;
205 size_t prevSize;
206
207 if (memory == NULL) {
208 errno = EINVAL;
209 return NULL;
210 }
211
212 /* man realloc: "If ptr is NULL, then the call is equivalent to
213 * malloc(size), for *all* values of size" */
214 if (ptr == NULL) {
215 return memory->malloc(memory, size);
216 }
217
218 /* man realloc: "If size is equal to zero, and ptr is *not* NULL,
219 * then the call is equivalent to free(ptr)." */
220 if (size == 0) {
221 memory->free(memory, ptr);
222 return NULL;
223 }
224
225 prevSize = *((size_t *)((char *)ptr - sizeof(size_t)));
226
227 /* Anything to do? */
228 if (size <= prevSize) {
229 return ptr;
230 }
231
232 newBuffer = memory->malloc(memory, size);
233 if (newBuffer == NULL) {
234 /* errno set by malloc */
235 return NULL;
236 }
237
238 memcpy(newBuffer, ptr, prevSize);
239
240 memory->free(memory, ptr);
241
242 return newBuffer;
243 }
244
245
246
uriDecorateFree(UriMemoryManager * memory,void * ptr)247 static void uriDecorateFree(UriMemoryManager * memory, void * ptr) {
248 UriMemoryManager * backend;
249
250 if ((ptr == NULL) || (memory == NULL)) {
251 return;
252 }
253
254 backend = (UriMemoryManager *)memory->userData;
255 if (backend == NULL) {
256 return;
257 }
258
259 backend->free(backend, (char *)ptr - sizeof(size_t));
260 }
261
262
263
uriCompleteMemoryManager(UriMemoryManager * memory,UriMemoryManager * backend)264 int uriCompleteMemoryManager(UriMemoryManager * memory,
265 UriMemoryManager * backend) {
266 if ((memory == NULL) || (backend == NULL)) {
267 return URI_ERROR_NULL;
268 }
269
270 if ((backend->malloc == NULL) || (backend->free == NULL)) {
271 return URI_ERROR_MEMORY_MANAGER_INCOMPLETE;
272 }
273
274 memory->calloc = uriEmulateCalloc;
275 memory->reallocarray = uriEmulateReallocarray;
276
277 memory->malloc = uriDecorateMalloc;
278 memory->realloc = uriDecorateRealloc;
279 memory->free = uriDecorateFree;
280
281 memory->userData = backend;
282
283 return URI_SUCCESS;
284 }
285
286
287
uriTestMemoryManager(UriMemoryManager * memory)288 int uriTestMemoryManager(UriMemoryManager * memory) {
289 const size_t mallocSize = 7;
290 const size_t callocNmemb = 3;
291 const size_t callocSize = 5;
292 const size_t callocTotalSize = callocNmemb * callocSize;
293 const size_t reallocSize = 11;
294 const size_t reallocarrayNmemb = 5;
295 const size_t reallocarraySize = 7;
296 const size_t reallocarrayTotal = reallocarrayNmemb * reallocarraySize;
297 size_t index;
298 char * buffer;
299
300 if (memory == NULL) {
301 return URI_ERROR_NULL;
302 }
303
304 if (uriMemoryManagerIsComplete(memory) != URI_TRUE) {
305 return URI_ERROR_MEMORY_MANAGER_INCOMPLETE;
306 }
307
308 /* malloc + free*/
309 buffer = memory->malloc(memory, mallocSize);
310 if (buffer == NULL) {
311 return URI_ERROR_MEMORY_MANAGER_FAULTY;
312 }
313 buffer[mallocSize - 1] = '\xF1';
314 memory->free(memory, buffer);
315 buffer = NULL;
316
317 /* calloc + free */
318 buffer = memory->calloc(memory, callocNmemb, callocSize);
319 if (buffer == NULL) {
320 return URI_ERROR_MEMORY_MANAGER_FAULTY;
321 }
322 for (index = 0; index < callocTotalSize; index++) { /* all zeros? */
323 if (buffer[index] != '\0') {
324 return URI_ERROR_MEMORY_MANAGER_FAULTY;
325 }
326 }
327 buffer[callocTotalSize - 1] = '\xF2';
328 memory->free(memory, buffer);
329 buffer = NULL;
330
331 /* malloc + realloc + free */
332 buffer = memory->malloc(memory, mallocSize);
333 if (buffer == NULL) {
334 return URI_ERROR_MEMORY_MANAGER_FAULTY;
335 }
336 for (index = 0; index < mallocSize; index++) {
337 buffer[index] = '\xF3';
338 }
339 buffer = memory->realloc(memory, buffer, reallocSize);
340 if (buffer == NULL) {
341 return URI_ERROR_MEMORY_MANAGER_FAULTY;
342 }
343 for (index = 0; index < mallocSize; index++) { /* previous content? */
344 if (buffer[index] != '\xF3') {
345 return URI_ERROR_MEMORY_MANAGER_FAULTY;
346 }
347 }
348 buffer[reallocSize - 1] = '\xF4';
349 memory->free(memory, buffer);
350 buffer = NULL;
351
352 /* malloc + realloc ptr!=NULL size==0 (equals free) */
353 buffer = memory->malloc(memory, mallocSize);
354 if (buffer == NULL) {
355 return URI_ERROR_MEMORY_MANAGER_FAULTY;
356 }
357 buffer[mallocSize - 1] = '\xF5';
358 memory->realloc(memory, buffer, 0);
359 buffer = NULL;
360
361 /* realloc ptr==NULL size!=0 (equals malloc) + free */
362 buffer = memory->realloc(memory, NULL, mallocSize);
363 if (buffer == NULL) {
364 return URI_ERROR_MEMORY_MANAGER_FAULTY;
365 }
366 buffer[mallocSize - 1] = '\xF6';
367 memory->free(memory, buffer);
368 buffer = NULL;
369
370 /* realloc ptr==NULL size==0 (equals malloc) + free */
371 buffer = memory->realloc(memory, NULL, 0);
372 if (buffer != NULL) {
373 memory->free(memory, buffer);
374 buffer = NULL;
375 }
376
377 /* malloc + reallocarray + free */
378 buffer = memory->malloc(memory, mallocSize);
379 if (buffer == NULL) {
380 return URI_ERROR_MEMORY_MANAGER_FAULTY;
381 }
382 for (index = 0; index < mallocSize; index++) {
383 buffer[index] = '\xF7';
384 }
385 buffer = memory->reallocarray(memory, buffer, reallocarrayNmemb,
386 reallocarraySize);
387 if (buffer == NULL) {
388 return URI_ERROR_MEMORY_MANAGER_FAULTY;
389 }
390 for (index = 0; index < mallocSize; index++) { /* previous content? */
391 if (buffer[index] != '\xF7') {
392 return URI_ERROR_MEMORY_MANAGER_FAULTY;
393 }
394 }
395 buffer[reallocarrayTotal - 1] = '\xF8';
396 memory->free(memory, buffer);
397 buffer = NULL;
398
399 /* malloc + reallocarray ptr!=NULL nmemb==0 size!=0 (equals free) */
400 buffer = memory->malloc(memory, mallocSize);
401 if (buffer == NULL) {
402 return URI_ERROR_MEMORY_MANAGER_FAULTY;
403 }
404 buffer[mallocSize - 1] = '\xF9';
405 memory->reallocarray(memory, buffer, 0, reallocarraySize);
406 buffer = NULL;
407
408 /* malloc + reallocarray ptr!=NULL nmemb!=0 size==0 (equals free) */
409 buffer = memory->malloc(memory, mallocSize);
410 if (buffer == NULL) {
411 return URI_ERROR_MEMORY_MANAGER_FAULTY;
412 }
413 buffer[mallocSize - 1] = '\xFA';
414 memory->reallocarray(memory, buffer, reallocarrayNmemb, 0);
415 buffer = NULL;
416
417 /* malloc + reallocarray ptr!=NULL nmemb==0 size==0 (equals free) */
418 buffer = memory->malloc(memory, mallocSize);
419 if (buffer == NULL) {
420 return URI_ERROR_MEMORY_MANAGER_FAULTY;
421 }
422 buffer[mallocSize - 1] = '\xFB';
423 memory->reallocarray(memory, buffer, 0, 0);
424 buffer = NULL;
425
426 /* reallocarray ptr==NULL nmemb!=0 size!=0 (equals malloc) + free */
427 buffer = memory->reallocarray(memory, NULL, callocNmemb, callocSize);
428 if (buffer == NULL) {
429 return URI_ERROR_MEMORY_MANAGER_FAULTY;
430 }
431 buffer[callocTotalSize - 1] = '\xFC';
432 memory->free(memory, buffer);
433 buffer = NULL;
434
435 /* reallocarray ptr==NULL nmemb==0 size!=0 (equals malloc) + free */
436 buffer = memory->reallocarray(memory, NULL, 0, callocSize);
437 if (buffer != NULL) {
438 memory->free(memory, buffer);
439 buffer = NULL;
440 }
441
442 /* reallocarray ptr==NULL nmemb!=0 size==0 (equals malloc) + free */
443 buffer = memory->reallocarray(memory, NULL, callocNmemb, 0);
444 if (buffer != NULL) {
445 memory->free(memory, buffer);
446 buffer = NULL;
447 }
448
449 /* reallocarray ptr==NULL nmemb==0 size==0 (equals malloc) + free */
450 buffer = memory->reallocarray(memory, NULL, 0, 0);
451 if (buffer != NULL) {
452 memory->free(memory, buffer);
453 buffer = NULL;
454 }
455
456 return URI_SUCCESS;
457 }
458
459
460
461 /*extern*/ UriMemoryManager defaultMemoryManager = {
462 uriDefaultMalloc,
463 uriDefaultCalloc,
464 uriDefaultRealloc,
465 uriDefaultReallocarray,
466 uriDefaultFree,
467 NULL /* userData */
468 };
469