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