X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Futil%2Fcommon_allocation.c;h=be2538c3f4c941661bb5e1c012df2baccf27210c;hb=e20eca334a33b8340524a8fa6ad1d6b606e1dd0c;hp=f39d84cb3693504efbe45b3fd9b2473992876e20;hpb=b60d9cfa7d42f0a933d7de137a2c8b17eaece4dd;p=oweals%2Fgnunet.git diff --git a/src/util/common_allocation.c b/src/util/common_allocation.c index f39d84cb3..be2538c3f 100644 --- a/src/util/common_allocation.c +++ b/src/util/common_allocation.c @@ -1,10 +1,10 @@ /* This file is part of GNUnet. - (C) 2001, 2002, 2003, 2005, 2006 Christian Grothoff (and other contributing authors) + Copyright (C) 2001, 2002, 2003, 2005, 2006 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2, or (at your + by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /** @@ -23,109 +23,401 @@ * @brief wrapper around malloc/free * @author Christian Grothoff */ - #include "platform.h" -#include "gnunet_common.h" +#include "gnunet_crypto_lib.h" +#if HAVE_MALLOC_H +#include +#endif +#if HAVE_MALLOC_MALLOC_H +#include +#endif + +#define LOG(kind,...) GNUNET_log_from (kind, "util-common-allocation",__VA_ARGS__) + +#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-common-allocation", syscall) #ifndef INT_MAX #define INT_MAX 0x7FFFFFFF #endif +#if 0 +#define W32_MEM_LIMIT 200000000 +#endif + +#ifdef W32_MEM_LIMIT +static LONG mem_used = 0; +#endif + /** * Allocate memory. Checks the return value, aborts if no more * memory is available. * * @param size how many bytes of memory to allocate, do NOT use - * this function (or GNUNET_malloc) to allocate more than several MB + * this function (or GNUNET_malloc()) to allocate more than several MB * of memory, if you are possibly needing a very large chunk use - * GNUNET_xmalloc_unchecked_ instead. - * @param filename where in the code was the call to GNUNET_array_grow - * @param linenumber where in the code was the call to GNUNET_array_grow + * #GNUNET_xmalloc_unchecked_() instead. + * @param filename where in the code was the call to GNUNET_malloc() + * @param linenumber where in the code was the call to GNUNET_malloc() * @return pointer to size bytes of memory */ void * -GNUNET_xmalloc_ (size_t size, const char *filename, int linenumber) +GNUNET_xmalloc_ (size_t size, + const char *filename, + int linenumber) +{ + void *ret; + + /* As a security precaution, we generally do not allow very large + * allocations using the default 'GNUNET_malloc()' macro */ + GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, + filename, + linenumber); + ret = GNUNET_xmalloc_unchecked_ (size, + filename, + linenumber); + if (NULL == ret) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, + "malloc"); + GNUNET_assert (0); + } + return ret; +} + + +/** + * Allocate memory for a two dimensional array in one block + * and set up pointers. Aborts if no more memory is available. + * Don't use GNUNET_xnew_array_2d_ directly. Use the + * #GNUNET_new_array_2d macro. + * The memory of the elements will be zero'ed out. + * + * @param n size of the first dimension + * @param m size of the second dimension + * @param elementSize size of a single element in bytes + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + * @return allocated memory, never NULL + */ +void ** +GNUNET_xnew_array_2d_ (size_t n, + size_t m, + size_t elementSize, + const char *filename, + int linenumber) +{ + /* use char pointer internally to avoid void pointer arithmetic warnings */ + char **ret = GNUNET_xmalloc_ (n * sizeof (void *) + /* 1. dim header */ + n * m * elementSize, /* element data */ + filename, linenumber); + + for (size_t i = 0; i < n; i++) + ret[i] = (char *)ret + /* base address */ + n * sizeof (void *) + /* skip 1. dim header */ + i * m * elementSize; /* skip to 2. dim row header */ + return (void **)ret; +} + + +/** + * Allocate memory for a three dimensional array in one block + * and set up pointers. Aborts if no more memory is available. + * Don't use GNUNET_xnew_array_3d_ directly. Use the + * #GNUNET_new_array_3d macro. + * The memory of the elements will be zero'ed out. + * + * @param n size of the first dimension + * @param m size of the second dimension + * @param o size of the third dimension + * @param elementSize size of a single element in bytes + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + * @return allocated memory, never NULL + */ +void *** +GNUNET_xnew_array_3d_ (size_t n, size_t m, size_t o, size_t elementSize, + const char *filename, int linenumber) +{ + /* use char pointer internally to avoid void pointer arithmetic warnings */ + char ***ret = GNUNET_xmalloc_ (n * sizeof (void **) + /* 1. dim header */ + n * m * sizeof (void *) + /* 2. dim header */ + n * m * o * elementSize, /* element data */ + filename, linenumber); + + for (size_t i = 0; i < n; i++) + { + /* need to cast to (char *) temporarily for byte level acuracy */ + ret[i] = (char **)((char *)ret + /* base address */ + n * sizeof (void **) + /* skip 1. dim header */ + i * m * sizeof (void *)); /* skip to 2. dim header */ + for (size_t j = 0; j < m; j++) + ret[i][j] = (char *)ret + /* base address */ + n * sizeof (void **) + /* skip 1. dim header */ + n * m * sizeof (void *) + /* skip 2. dim header */ + i * m * o * elementSize + /* skip to 2. dim part */ + j * o * elementSize; /* skip to 3. dim row data */ + } + return (void ***)ret; +} + + +/** + * Allocate and initialize memory. Checks the return value, aborts if no more + * memory is available. Don't use #GNUNET_xmemdup_() directly. Use the + * GNUNET_memdup() macro. + * + * @param buf buffer to initialize from (must contain size bytes) + * @param size number of bytes to allocate + * @param filename where is this call being made (for debugging) + * @param linenumber line where this call is being made (for debugging) + * @return allocated memory, never NULL + */ +void * +GNUNET_xmemdup_ (const void *buf, + size_t size, + const char *filename, + int linenumber) { + void *ret; + /* As a security precaution, we generally do not allow very large - allocations using the default 'GNUNET_malloc' macro */ - GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, - linenumber); - return GNUNET_xmalloc_unchecked_ (size, filename, linenumber); + * allocations here */ + GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber); +#ifdef W32_MEM_LIMIT + size += sizeof (size_t); + if (mem_used + size > W32_MEM_LIMIT) + return NULL; +#endif + GNUNET_assert_at (size < INT_MAX, filename, linenumber); + ret = malloc (size); + if (ret == NULL) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc"); + GNUNET_assert (0); + } +#ifdef W32_MEM_LIMIT + *((size_t *) ret) = size; + ret = &((size_t *) ret)[1]; + mem_used += size; +#endif + GNUNET_memcpy (ret, buf, size); + return ret; } + +/** + * Wrapper around malloc(). Allocates size bytes of memory. + * The memory will be zero'ed out. + * + * @param size the number of bytes to allocate + * @param filename where in the code was the call to GNUNET_malloc_unchecked() + * @param linenumber where in the code was the call to GNUNET_malloc_unchecked() + * @return pointer to size bytes of memory, NULL if we do not have enough memory + */ void * -GNUNET_xmalloc_unchecked_ (size_t size, const char *filename, int linenumber) +GNUNET_xmalloc_unchecked_ (size_t size, + const char *filename, + int linenumber) { void *result; - GNUNET_assert_at (size < INT_MAX, filename, linenumber); + (void) filename; + (void) linenumber; +#ifdef W32_MEM_LIMIT + size += sizeof (size_t); + if (mem_used + size > W32_MEM_LIMIT) + return NULL; +#endif + result = malloc (size); - if (result == NULL) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "malloc"); - abort (); - } + if (NULL == result) + return NULL; memset (result, 0, size); + +#ifdef W32_MEM_LIMIT + *((size_t *) result) = size; + result = &((size_t *) result)[1]; + mem_used += size; +#endif + return result; } + /** * Reallocate memory. Checks the return value, aborts if no more * memory is available. + * The content of the intersection of the new and old size will be unchanged. * - * @ptr the pointer to reallocate - * @param size how many bytes of memory to allocate - * @param filename where in the code was the call to GNUNET_realloc - * @param linenumber where in the code was the call to GNUNET_realloc + * @param ptr the pointer to reallocate + * @param n how many bytes of memory to allocate + * @param filename where in the code was the call to GNUNET_realloc() + * @param linenumber where in the code was the call to GNUNET_realloc() * @return pointer to size bytes of memory */ void * GNUNET_xrealloc_ (void *ptr, - const size_t n, const char *filename, int linenumber) + size_t n, + const char *filename, + int linenumber) { + (void) filename; + (void) linenumber; + +#ifdef W32_MEM_LIMIT + n += sizeof (size_t); + ptr = &((size_t *) ptr)[-1]; + mem_used = mem_used - *((size_t *) ptr) + n; +#endif ptr = realloc (ptr, n); - if (!ptr) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "realloc"); - abort (); - } + if ((NULL == ptr) && (n > 0)) + { + LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, + "realloc"); + GNUNET_assert (0); + } +#ifdef W32_MEM_LIMIT + ptr = &((size_t *) ptr)[1]; +#endif return ptr; } + +# if __BYTE_ORDER == __LITTLE_ENDIAN +#define BAADFOOD_STR "\x0D\xF0\xAD\xBA" +#endif +# if __BYTE_ORDER == __BIG_ENDIAN +#define BAADFOOD_STR "\xBA\xAD\xF0\x0D" +#endif + +#if WINDOWS +#define M_SIZE(p) _msize (p) +#endif +#if HAVE_MALLOC_NP_H +#include +#endif +#if HAVE_MALLOC_USABLE_SIZE +#define M_SIZE(p) malloc_usable_size (p) +#elif HAVE_MALLOC_SIZE +#define M_SIZE(p) malloc_size (p) +#endif + /** * Free memory. Merely a wrapper for the case that we * want to keep track of allocations. * * @param ptr the pointer to free - * @param filename where in the code was the call to GNUNET_array_grow - * @param linenumber where in the code was the call to GNUNET_array_grow + * @param filename where in the code was the call to GNUNET_free + * @param linenumber where in the code was the call to GNUNET_free */ void -GNUNET_xfree_ (void *ptr, const char *filename, int linenumber) +GNUNET_xfree_ (void *ptr, + const char *filename, + int linenumber) { - GNUNET_assert_at (ptr != NULL, filename, linenumber); + GNUNET_assert_at (NULL != ptr, + filename, + linenumber); +#ifdef W32_MEM_LIMIT + ptr = &((size_t *) ptr)[-1]; + mem_used -= *((size_t *) ptr); +#endif +#if defined(M_SIZE) +#if ENABLE_POISONING + { + const uint64_t baadfood = GNUNET_ntohll (0xBAADF00DBAADF00DLL); + uint64_t *base = ptr; + size_t s = M_SIZE (ptr); + size_t i; + + for (i=0;i newCount, filename, linenumber); size = newCount * elementSize; - if (size == 0) - { - tmp = NULL; - } + if (0 == size) + { + tmp = NULL; + } else + { + tmp = GNUNET_xmalloc_ (size, filename, linenumber); + if (NULL != *old) { - tmp = GNUNET_xmalloc_ (size, filename, linenumber); - memset (tmp, 0, size); /* client code should not rely on this, though... */ - if (*oldCount > newCount) - *oldCount = newCount; /* shrink is also allowed! */ - memcpy (tmp, *old, elementSize * (*oldCount)); + GNUNET_memcpy (tmp, *old, elementSize * GNUNET_MIN(*oldCount, newCount)); } + } - if (*old != NULL) - { - GNUNET_xfree_ (*old, filename, linenumber); - } + if (NULL != *old) + { + GNUNET_xfree_ (*old, filename, linenumber); + } *old = tmp; *oldCount = newCount; } +/** + * Like asprintf(), just portable. + * + * @param buf set to a buffer of sufficient size (allocated, caller must free) + * @param format format string (see printf(), fprintf(), etc.) + * @param ... data for format string + * @return number of bytes in `*@a buf`, excluding 0-termination + */ int -GNUNET_asprintf (char **buf, const char *format, ...) +GNUNET_asprintf (char **buf, + const char *format, + ...) { int ret; va_list args; @@ -187,16 +491,54 @@ GNUNET_asprintf (char **buf, const char *format, ...) return ret; } + +/** + * Like snprintf(), just aborts if the buffer is of insufficient size. + * + * @param buf pointer to buffer that is written to + * @param size number of bytes in buf + * @param format format strings + * @param ... data for format string + * @return number of bytes written to buf or negative value on error + */ int -GNUNET_snprintf (char *buf, size_t size, const char *format, ...) +GNUNET_snprintf (char *buf, + size_t size, + const char *format, ...) { int ret; va_list args; va_start (args, format); - ret = VSNPRINTF (buf, size, format, args); + ret = VSNPRINTF (buf, + size, + format, + args); va_end (args); - GNUNET_assert (ret <= size); + GNUNET_assert ( (ret >= 0) && + (((size_t) ret) < size) ); + return ret; +} + + +/** + * Create a copy of the given message. + * + * @param msg message to copy + * @return duplicate of the message + */ +struct GNUNET_MessageHeader * +GNUNET_copy_message (const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_MessageHeader *ret; + uint16_t msize; + + msize = ntohs (msg->size); + GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); + ret = GNUNET_malloc (msize); + GNUNET_memcpy (ret, + msg, + msize); return ret; }