diff options
Diffstat (limited to 'src/UriMemory.c')
-rw-r--r-- | src/UriMemory.c | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/src/UriMemory.c b/src/UriMemory.c new file mode 100644 index 0000000..5e6bcc4 --- /dev/null +++ b/src/UriMemory.c @@ -0,0 +1,470 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2018, Weijia Song <songweijia@gmail.com> + * Copyright (C) 2018, Sebastian Pipping <sebastian@pipping.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * * Neither the name of the <ORGANIZATION> nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file UriMemory.c + * Holds memory manager implementation. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if HAVE_REALLOCARRAY +# ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +# endif +#endif + +#include <errno.h> +#include <stdlib.h> + + + +#ifndef URI_DOXYGEN +# include "UriMemory.h" +#endif + + + +#define URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size) \ + do { \ + /* check for unsigned overflow */ \ + if ((nmemb != 0) && (total_size / nmemb != size)) { \ + errno = ENOMEM; \ + return NULL; \ + } \ + } while (0) + + + +static void * uriDefaultMalloc(UriMemoryManager * URI_UNUSED(memory), + size_t size) { + return malloc(size); +} + + + +static void * uriDefaultCalloc(UriMemoryManager * URI_UNUSED(memory), + size_t nmemb, size_t size) { + return calloc(nmemb, size); +} + + + +static void * uriDefaultRealloc(UriMemoryManager * URI_UNUSED(memory), + void * ptr, size_t size) { + return realloc(ptr, size); +} + + + +static void * uriDefaultReallocarray(UriMemoryManager * URI_UNUSED(memory), + void * ptr, size_t nmemb, size_t size) { +#if HAVE_REALLOCARRAY + return reallocarray(ptr, nmemb, size); +#else + const size_t total_size = nmemb * size; + + URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */ + + return realloc(ptr, total_size); +#endif +} + + + +static void uriDefaultFree(UriMemoryManager * URI_UNUSED(memory), + void * ptr) { + free(ptr); +} + + + +UriBool uriMemoryManagerIsComplete(const UriMemoryManager * memory) { + return (memory + && memory->malloc + && memory->calloc + && memory->realloc + && memory->reallocarray + && memory->free) ? URI_TRUE : URI_FALSE; +} + + + +void * uriEmulateCalloc(UriMemoryManager * memory, size_t nmemb, size_t size) { + void * buffer; + const size_t total_size = nmemb * size; + + if (memory == NULL) { + errno = EINVAL; + return NULL; + } + + URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */ + + buffer = memory->malloc(memory, total_size); + if (buffer == NULL) { + /* errno set by malloc */ + return NULL; + } + memset(buffer, 0, total_size); + return buffer; +} + + + +void * uriEmulateReallocarray(UriMemoryManager * memory, + void * ptr, size_t nmemb, size_t size) { + const size_t total_size = nmemb * size; + + if (memory == NULL) { + errno = EINVAL; + return NULL; + } + + URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size); /* may return */ + + return memory->realloc(memory, ptr, total_size); +} + + + +static void * uriDecorateMalloc(UriMemoryManager * memory, + size_t size) { + UriMemoryManager * backend; + const size_t extraBytes = sizeof(size_t); + void * buffer; + + if (memory == NULL) { + errno = EINVAL; + return NULL; + } + + /* check for unsigned overflow */ + if (size > ((size_t)-1) - extraBytes) { + errno = ENOMEM; + return NULL; + } + + backend = (UriMemoryManager *)memory->userData; + if (backend == NULL) { + errno = EINVAL; + return NULL; + } + + buffer = backend->malloc(backend, extraBytes + size); + if (buffer == NULL) { + return NULL; + } + + *(size_t *)buffer = size; + + return (char *)buffer + extraBytes; +} + + + +static void * uriDecorateRealloc(UriMemoryManager * memory, + void * ptr, size_t size) { + void * newBuffer; + size_t prevSize; + + if (memory == NULL) { + errno = EINVAL; + return NULL; + } + + /* man realloc: "If ptr is NULL, then the call is equivalent to + * malloc(size), for *all* values of size" */ + if (ptr == NULL) { + return memory->malloc(memory, size); + } + + /* man realloc: "If size is equal to zero, and ptr is *not* NULL, + * then the call is equivalent to free(ptr)." */ + if (size == 0) { + memory->free(memory, ptr); + return NULL; + } + + prevSize = *((size_t *)((char *)ptr - sizeof(size_t))); + + /* Anything to do? */ + if (size <= prevSize) { + return ptr; + } + + newBuffer = memory->malloc(memory, size); + if (newBuffer == NULL) { + /* errno set by malloc */ + return NULL; + } + + memcpy(newBuffer, ptr, prevSize); + + memory->free(memory, ptr); + + return newBuffer; +} + + + +static void uriDecorateFree(UriMemoryManager * memory, void * ptr) { + UriMemoryManager * backend; + + if ((ptr == NULL) || (memory == NULL)) { + return; + } + + backend = (UriMemoryManager *)memory->userData; + if (backend == NULL) { + return; + } + + backend->free(backend, (char *)ptr - sizeof(size_t)); +} + + + +int uriCompleteMemoryManager(UriMemoryManager * memory, + UriMemoryManager * backend) { + if ((memory == NULL) || (backend == NULL)) { + return URI_ERROR_NULL; + } + + if ((backend->malloc == NULL) || (backend->free == NULL)) { + return URI_ERROR_MEMORY_MANAGER_INCOMPLETE; + } + + memory->calloc = uriEmulateCalloc; + memory->reallocarray = uriEmulateReallocarray; + + memory->malloc = uriDecorateMalloc; + memory->realloc = uriDecorateRealloc; + memory->free = uriDecorateFree; + + memory->userData = backend; + + return URI_SUCCESS; +} + + + +int uriTestMemoryManager(UriMemoryManager * memory) { + const size_t mallocSize = 7; + const size_t callocNmemb = 3; + const size_t callocSize = 5; + const size_t callocTotalSize = callocNmemb * callocSize; + const size_t reallocSize = 11; + const size_t reallocarrayNmemb = 5; + const size_t reallocarraySize = 7; + const size_t reallocarrayTotal = reallocarrayNmemb * reallocarraySize; + size_t index; + char * buffer; + + if (memory == NULL) { + return URI_ERROR_NULL; + } + + if (uriMemoryManagerIsComplete(memory) != URI_TRUE) { + return URI_ERROR_MEMORY_MANAGER_INCOMPLETE; + } + + /* malloc + free*/ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xF1'; + memory->free(memory, buffer); + buffer = NULL; + + /* calloc + free */ + buffer = memory->calloc(memory, callocNmemb, callocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + for (index = 0; index < callocTotalSize; index++) { /* all zeros? */ + if (buffer[index] != '\0') { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + } + buffer[callocTotalSize - 1] = '\xF2'; + memory->free(memory, buffer); + buffer = NULL; + + /* malloc + realloc + free */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + for (index = 0; index < mallocSize; index++) { + buffer[index] = '\xF3'; + } + buffer = memory->realloc(memory, buffer, reallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + for (index = 0; index < mallocSize; index++) { /* previous content? */ + if (buffer[index] != '\xF3') { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + } + buffer[reallocSize - 1] = '\xF4'; + memory->free(memory, buffer); + buffer = NULL; + + /* malloc + realloc ptr!=NULL size==0 (equals free) */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xF5'; + memory->realloc(memory, buffer, 0); + buffer = NULL; + + /* realloc ptr==NULL size!=0 (equals malloc) + free */ + buffer = memory->realloc(memory, NULL, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xF6'; + memory->free(memory, buffer); + buffer = NULL; + + /* realloc ptr==NULL size==0 (equals malloc) + free */ + buffer = memory->realloc(memory, NULL, 0); + if (buffer != NULL) { + memory->free(memory, buffer); + buffer = NULL; + } + + /* malloc + reallocarray + free */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + for (index = 0; index < mallocSize; index++) { + buffer[index] = '\xF7'; + } + buffer = memory->reallocarray(memory, buffer, reallocarrayNmemb, + reallocarraySize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + for (index = 0; index < mallocSize; index++) { /* previous content? */ + if (buffer[index] != '\xF7') { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + } + buffer[reallocarrayTotal - 1] = '\xF8'; + memory->free(memory, buffer); + buffer = NULL; + + /* malloc + reallocarray ptr!=NULL nmemb==0 size!=0 (equals free) */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xF9'; + memory->reallocarray(memory, buffer, 0, reallocarraySize); + buffer = NULL; + + /* malloc + reallocarray ptr!=NULL nmemb!=0 size==0 (equals free) */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xFA'; + memory->reallocarray(memory, buffer, reallocarrayNmemb, 0); + buffer = NULL; + + /* malloc + reallocarray ptr!=NULL nmemb==0 size==0 (equals free) */ + buffer = memory->malloc(memory, mallocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[mallocSize - 1] = '\xFB'; + memory->reallocarray(memory, buffer, 0, 0); + buffer = NULL; + + /* reallocarray ptr==NULL nmemb!=0 size!=0 (equals malloc) + free */ + buffer = memory->reallocarray(memory, NULL, callocNmemb, callocSize); + if (buffer == NULL) { + return URI_ERROR_MEMORY_MANAGER_FAULTY; + } + buffer[callocTotalSize - 1] = '\xFC'; + memory->free(memory, buffer); + buffer = NULL; + + /* reallocarray ptr==NULL nmemb==0 size!=0 (equals malloc) + free */ + buffer = memory->reallocarray(memory, NULL, 0, callocSize); + if (buffer != NULL) { + memory->free(memory, buffer); + buffer = NULL; + } + + /* reallocarray ptr==NULL nmemb!=0 size==0 (equals malloc) + free */ + buffer = memory->reallocarray(memory, NULL, callocNmemb, 0); + if (buffer != NULL) { + memory->free(memory, buffer); + buffer = NULL; + } + + /* reallocarray ptr==NULL nmemb==0 size==0 (equals malloc) + free */ + buffer = memory->reallocarray(memory, NULL, 0, 0); + if (buffer != NULL) { + memory->free(memory, buffer); + buffer = NULL; + } + + return URI_SUCCESS; +} + + + +/*extern*/ UriMemoryManager defaultMemoryManager = { + uriDefaultMalloc, + uriDefaultCalloc, + uriDefaultRealloc, + uriDefaultReallocarray, + uriDefaultFree, + NULL /* userData */ +}; |