summaryrefslogtreecommitdiff
path: root/src/UriMemory.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/UriMemory.c')
-rw-r--r--src/UriMemory.c470
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 */
+};