Merge branch 'master' of ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / util / common_allocation.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001, 2002, 2003, 2005, 2006 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file util/common_allocation.c
23  * @brief wrapper around malloc/free
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_crypto_lib.h"
28 #if HAVE_MALLOC_H
29 #include <malloc.h>
30 #endif
31 #if HAVE_MALLOC_MALLOC_H
32 #include <malloc/malloc.h>
33 #endif
34
35 #define LOG(kind,...) GNUNET_log_from (kind, "util-common-allocation",__VA_ARGS__)
36
37 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-common-allocation", syscall)
38
39 #ifndef INT_MAX
40 #define INT_MAX 0x7FFFFFFF
41 #endif
42
43 #if 0
44 #define W32_MEM_LIMIT 200000000
45 #endif
46
47 #ifdef W32_MEM_LIMIT
48 static LONG mem_used = 0;
49 #endif
50
51 /**
52  * Allocate memory. Checks the return value, aborts if no more
53  * memory is available.
54  *
55  * @param size how many bytes of memory to allocate, do NOT use
56  *  this function (or GNUNET_malloc()) to allocate more than several MB
57  *  of memory, if you are possibly needing a very large chunk use
58  *  #GNUNET_xmalloc_unchecked_() instead.
59  * @param filename where in the code was the call to GNUNET_malloc()
60  * @param linenumber where in the code was the call to GNUNET_malloc()
61  * @return pointer to size bytes of memory
62  */
63 void *
64 GNUNET_xmalloc_ (size_t size,
65                  const char *filename,
66                  int linenumber)
67 {
68   void *ret;
69
70   /* As a security precaution, we generally do not allow very large
71    * allocations using the default 'GNUNET_malloc()' macro */
72   GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED,
73                     filename,
74                     linenumber);
75   ret = GNUNET_xmalloc_unchecked_ (size,
76                                    filename,
77                                    linenumber);
78   if (NULL == ret)
79   {
80     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
81                   "malloc");
82     GNUNET_assert (0);
83   }
84   return ret;
85 }
86
87
88 /**
89  * Allocate memory for a two dimensional array in one block
90  * and set up pointers. Aborts if no more memory is available.
91  * Don't use GNUNET_xnew_array_2d_ directly. Use the
92  * #GNUNET_new_array_2d macro.
93  * The memory of the elements will be zero'ed out.
94  *
95  * @param n size of the first dimension
96  * @param m size of the second dimension
97  * @param elementSize size of a single element in bytes
98  * @param filename where is this call being made (for debugging)
99  * @param linenumber line where this call is being made (for debugging)
100  * @return allocated memory, never NULL
101  */
102 void **
103 GNUNET_xnew_array_2d_ (size_t n, size_t m, size_t elementSize,
104                        const char *filename, int linenumber)
105 {
106         /* use char pointer internally to avoid void pointer arithmetic warnings */
107         char **ret = GNUNET_xmalloc_ (n * sizeof (void *) +  /* 1. dim header */
108                                       n * m * elementSize,   /* element data */
109                                       filename, linenumber);
110
111         for (size_t i = 0; i < n; i++)
112                 ret[i] = (char *)ret +          /* base address */
113                          n * sizeof (void *) +  /* skip 1. dim header */
114                          i * m * elementSize;   /* skip to 2. dim row header */
115         return (void **)ret;
116 }
117
118
119 /**
120  * Allocate memory for a three dimensional array in one block
121  * and set up pointers. Aborts if no more memory is available.
122  * Don't use GNUNET_xnew_array_3d_ directly. Use the
123  * #GNUNET_new_array_3d macro.
124  * The memory of the elements will be zero'ed out.
125  *
126  * @param n size of the first dimension
127  * @param m size of the second dimension
128  * @param o size of the third dimension
129  * @param elementSize size of a single element in bytes
130  * @param filename where is this call being made (for debugging)
131  * @param linenumber line where this call is being made (for debugging)
132  * @return allocated memory, never NULL
133  */
134 void ***
135 GNUNET_xnew_array_3d_ (size_t n, size_t m, size_t o, size_t elementSize,
136                        const char *filename, int linenumber)
137 {
138         /* use char pointer internally to avoid void pointer arithmetic warnings */
139         char ***ret = GNUNET_xmalloc_ (n * sizeof (void **) +    /* 1. dim header */
140                                        n * m * sizeof (void *) + /* 2. dim header */
141                                        n * m * o * elementSize,  /* element data */
142                                        filename, linenumber);
143
144         for (size_t i = 0; i < n; i++)
145         {
146                 /* need to cast to (char *) temporarily for byte level acuracy */
147                 ret[i] = (char **)((char *)ret +             /* base address */
148                                    n * sizeof (void **) +    /* skip 1. dim header */
149                                    i * m * sizeof (void *)); /* skip to 2. dim header */
150                 for (size_t j = 0; j < m; j++)
151                         ret[i][j] = (char *)ret +              /* base address */
152                                     n * sizeof (void **) +     /* skip 1. dim header */
153                                     n * m * sizeof (void *) +  /* skip 2. dim header */
154                                     i * m * o * elementSize +  /* skip to 2. dim part */
155                                         j * o * elementSize;   /* skip to 3. dim row data */
156         }
157         return (void ***)ret;
158 }
159
160
161 /**
162  * Allocate and initialize memory. Checks the return value, aborts if no more
163  * memory is available.  Don't use #GNUNET_xmemdup_() directly. Use the
164  * GNUNET_memdup() macro.
165  *
166  * @param buf buffer to initialize from (must contain size bytes)
167  * @param size number of bytes to allocate
168  * @param filename where is this call being made (for debugging)
169  * @param linenumber line where this call is being made (for debugging)
170  * @return allocated memory, never NULL
171  */
172 void *
173 GNUNET_xmemdup_ (const void *buf,
174                  size_t size,
175                  const char *filename,
176                  int linenumber)
177 {
178   void *ret;
179
180   /* As a security precaution, we generally do not allow very large
181    * allocations here */
182   GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber);
183 #ifdef W32_MEM_LIMIT
184   size += sizeof (size_t);
185   if (mem_used + size > W32_MEM_LIMIT)
186     return NULL;
187 #endif
188   GNUNET_assert_at (size < INT_MAX, filename, linenumber);
189   ret = malloc (size);
190   if (ret == NULL)
191   {
192     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc");
193     GNUNET_assert (0);
194   }
195 #ifdef W32_MEM_LIMIT
196   *((size_t *) ret) = size;
197   ret = &((size_t *) ret)[1];
198   mem_used += size;
199 #endif
200   GNUNET_memcpy (ret, buf, size);
201   return ret;
202 }
203
204
205 /**
206  * Wrapper around malloc(). Allocates size bytes of memory.
207  * The memory will be zero'ed out.
208  *
209  * @param size the number of bytes to allocate
210  * @param filename where in the code was the call to GNUNET_malloc_unchecked()
211  * @param linenumber where in the code was the call to GNUNET_malloc_unchecked()
212  * @return pointer to size bytes of memory, NULL if we do not have enough memory
213  */
214 void *
215 GNUNET_xmalloc_unchecked_ (size_t size,
216                            const char *filename,
217                            int linenumber)
218 {
219   void *result;
220
221 #ifdef W32_MEM_LIMIT
222   size += sizeof (size_t);
223   if (mem_used + size > W32_MEM_LIMIT)
224     return NULL;
225 #endif
226
227   result = malloc (size);
228   if (NULL == result)
229     return NULL;
230   memset (result, 0, size);
231
232 #ifdef W32_MEM_LIMIT
233   *((size_t *) result) = size;
234   result = &((size_t *) result)[1];
235   mem_used += size;
236 #endif
237
238   return result;
239 }
240
241
242 /**
243  * Reallocate memory. Checks the return value, aborts if no more
244  * memory is available.
245  * The content of the intersection of the new and old size will be unchanged.
246  *
247  * @param ptr the pointer to reallocate
248  * @param n how many bytes of memory to allocate
249  * @param filename where in the code was the call to GNUNET_realloc()
250  * @param linenumber where in the code was the call to GNUNET_realloc()
251  * @return pointer to size bytes of memory
252  */
253 void *
254 GNUNET_xrealloc_ (void *ptr,
255                   size_t n,
256                   const char *filename,
257                   int linenumber)
258 {
259 #ifdef W32_MEM_LIMIT
260   n += sizeof (size_t);
261   ptr = &((size_t *) ptr)[-1];
262   mem_used = mem_used - *((size_t *) ptr) + n;
263 #endif
264   ptr = realloc (ptr, n);
265   if ((NULL == ptr) && (n > 0))
266   {
267     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "realloc");
268     GNUNET_assert (0);
269   }
270 #ifdef W32_MEM_LIMIT
271   ptr = &((size_t *) ptr)[1];
272 #endif
273   return ptr;
274 }
275
276
277 # if __BYTE_ORDER == __LITTLE_ENDIAN
278 #define BAADFOOD_STR "\x0D\xF0\xAD\xBA"
279 #endif
280 # if __BYTE_ORDER == __BIG_ENDIAN
281 #define BAADFOOD_STR "\xBA\xAD\xF0\x0D"
282 #endif
283
284 #if WINDOWS
285 #define M_SIZE(p) _msize (p)
286 #endif
287 #if HAVE_MALLOC_NP_H
288 #include <malloc_np.h>
289 #endif
290 #if HAVE_MALLOC_USABLE_SIZE
291 #define M_SIZE(p) malloc_usable_size (p)
292 #elif HAVE_MALLOC_SIZE
293 #define M_SIZE(p) malloc_size (p)
294 #endif
295
296 /**
297  * Free memory. Merely a wrapper for the case that we
298  * want to keep track of allocations.
299  *
300  * @param ptr the pointer to free
301  * @param filename where in the code was the call to GNUNET_free
302  * @param linenumber where in the code was the call to GNUNET_free
303  */
304 void
305 GNUNET_xfree_ (void *ptr,
306                const char *filename,
307                int linenumber)
308 {
309   GNUNET_assert_at (NULL != ptr,
310                     filename,
311                     linenumber);
312 #ifdef W32_MEM_LIMIT
313   ptr = &((size_t *) ptr)[-1];
314   mem_used -= *((size_t *) ptr);
315 #endif
316 #if defined(M_SIZE)
317 #if ENABLE_POISONING
318   {
319     const uint64_t baadfood = GNUNET_ntohll (0xBAADF00DBAADF00DLL);
320     uint64_t *base = ptr;
321     size_t s = M_SIZE (ptr);
322     size_t i;
323
324     for (i=0;i<s/8;i++)
325       base[i] = baadfood;
326     GNUNET_memcpy (&base[s/8], &baadfood, s % 8);
327   }
328 #endif
329 #endif
330   free (ptr);
331 }
332
333
334 /**
335  * Dup a string (same semantics as strdup).
336  *
337  * @param str the string to dup
338  * @param filename where in the code was the call to GNUNET_strdup()
339  * @param linenumber where in the code was the call to GNUNET_strdup()
340  * @return `strdup(@a str)`
341  */
342 char *
343 GNUNET_xstrdup_ (const char *str,
344                  const char *filename,
345                  int linenumber)
346 {
347   char *res;
348   size_t slen;
349
350   GNUNET_assert_at (str != NULL,
351                     filename,
352                     linenumber);
353   slen = strlen (str) + 1;
354   res = GNUNET_xmalloc_ (slen,
355                          filename,
356                          linenumber);
357   GNUNET_memcpy (res,
358           str,
359           slen);
360   return res;
361 }
362
363
364 #if ! HAVE_STRNLEN
365 static size_t
366 strnlen (const char *s,
367          size_t n)
368 {
369   const char *e;
370
371   e = memchr (s, '\0', n);
372   if (NULL == e)
373     return n;
374   return e - s;
375 }
376 #endif
377
378
379 /**
380  * Dup partially a string (same semantics as strndup).
381  *
382  * @param str the string to dup
383  * @param len the length of the string to dup
384  * @param filename where in the code was the call to GNUNET_strndup()
385  * @param linenumber where in the code was the call to GNUNET_strndup()
386  * @return `strndup(@a str,@a len)`
387  */
388 char *
389 GNUNET_xstrndup_ (const char *str,
390                   size_t len,
391                   const char *filename,
392                   int linenumber)
393 {
394   char *res;
395
396   if (0 == len)
397     return GNUNET_strdup ("");
398   GNUNET_assert_at (NULL != str,
399                     filename,
400                     linenumber);
401   len = strnlen (str,
402                  len);
403   res = GNUNET_xmalloc_ (len + 1,
404                          filename,
405                          linenumber);
406   GNUNET_memcpy (res, str, len);
407   /* res[len] = '\0'; 'malloc' zeros out anyway */
408   return res;
409 }
410
411
412 /**
413  * Grow an array.  Grows old by (*oldCount-newCount)*elementSize bytes
414  * and sets *oldCount to newCount.
415  *
416  * @param old address of the pointer to the array
417  *        *old may be NULL
418  * @param elementSize the size of the elements of the array
419  * @param oldCount address of the number of elements in the *old array
420  * @param newCount number of elements in the new array, may be 0
421  * @param filename where in the code was the call to GNUNET_array_grow()
422  * @param linenumber where in the code was the call to GNUNET_array_grow()
423  */
424 void
425 GNUNET_xgrow_ (void **old,
426                size_t elementSize,
427                unsigned int *oldCount,
428          unsigned int newCount,
429                const char *filename,
430                int linenumber)
431 {
432   void *tmp;
433   size_t size;
434
435   GNUNET_assert_at (INT_MAX / elementSize > newCount, filename, linenumber);
436   size = newCount * elementSize;
437   if (0 == size)
438   {
439     tmp = NULL;
440   }
441   else
442   {
443     tmp = GNUNET_xmalloc_ (size, filename, linenumber);
444     if (NULL != *old)
445     {
446       GNUNET_memcpy (tmp, *old, elementSize * GNUNET_MIN(*oldCount, newCount));
447     }
448   }
449
450   if (NULL != *old)
451   {
452     GNUNET_xfree_ (*old, filename, linenumber);
453   }
454   *old = tmp;
455   *oldCount = newCount;
456 }
457
458
459 /**
460  * Like asprintf(), just portable.
461  *
462  * @param buf set to a buffer of sufficient size (allocated, caller must free)
463  * @param format format string (see printf(), fprintf(), etc.)
464  * @param ... data for format string
465  * @return number of bytes in `*@a buf`, excluding 0-termination
466  */
467 int
468 GNUNET_asprintf (char **buf,
469                  const char *format,
470                  ...)
471 {
472   int ret;
473   va_list args;
474
475   va_start (args, format);
476   ret = VSNPRINTF (NULL, 0, format, args);
477   va_end (args);
478   *buf = GNUNET_malloc (ret + 1);
479   va_start (args, format);
480   ret = VSPRINTF (*buf, format, args);
481   va_end (args);
482   return ret;
483 }
484
485
486 /**
487  * Like snprintf(), just aborts if the buffer is of insufficient size.
488  *
489  * @param buf pointer to buffer that is written to
490  * @param size number of bytes in buf
491  * @param format format strings
492  * @param ... data for format string
493  * @return number of bytes written to buf or negative value on error
494  */
495 int
496 GNUNET_snprintf (char *buf,
497                  size_t size,
498                  const char *format, ...)
499 {
500   int ret;
501   va_list args;
502
503   va_start (args, format);
504   ret = VSNPRINTF (buf, size, format, args);
505   va_end (args);
506   GNUNET_assert (ret < size);
507   return ret;
508 }
509
510
511 /**
512  * Create a copy of the given message.
513  *
514  * @param msg message to copy
515  * @return duplicate of the message
516  */
517 struct GNUNET_MessageHeader *
518 GNUNET_copy_message (const struct GNUNET_MessageHeader *msg)
519 {
520   struct GNUNET_MessageHeader *ret;
521   uint16_t msize;
522
523   msize = ntohs (msg->size);
524   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
525   ret = GNUNET_malloc (msize);
526   GNUNET_memcpy (ret, msg, msize);
527   return ret;
528 }
529
530
531 /* end of common_allocation.c */