ack florian
[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",__VA_ARGS__)
36
37 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", 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  * @return allocated memory, never NULL
99  */
100 void **
101 GNUNET_xnew_array_2d_ (size_t n, size_t m, size_t elementSize)
102 {
103         /* use char pointer internally to avoid void pointer arithmetic warnings */
104         char **ret = GNUNET_malloc (n * sizeof (void *) +  /* 1. dim header */
105                                     n * m * elementSize);  /* element data */
106
107         for (size_t i = 0; i < n; i++)
108                 ret[i] = (char *)ret +          /* base address */
109                          n * sizeof (void *) +  /* skip 1. dim header */
110                          i * m * elementSize;   /* skip to 2. dim row header */
111         return (void **)ret;
112 }
113
114
115 /**
116  * Allocate memory for a three dimensional array in one block
117  * and set up pointers. Aborts if no more memory is available.
118  * Don't use GNUNET_xnew_array_3d_ directly. Use the
119  * #GNUNET_new_array_3d macro.
120  * The memory of the elements will be zero'ed out.
121  *
122  * @param n size of the first dimension
123  * @param m size of the second dimension
124  * @param o size of the third dimension
125  * @param elementSize size of a single element in bytes
126  * @return allocated memory, never NULL
127  */
128 void ***
129 GNUNET_xnew_array_3d_ (size_t n, size_t m, size_t o, size_t elementSize)
130 {
131         /* use char pointer internally to avoid void pointer arithmetic warnings */
132         char ***ret = GNUNET_malloc (n * sizeof (void **) +     /* 1. dim header */
133                                      n * m * sizeof (void *) +  /* 2. dim header */
134                                      n * m * o * elementSize);  /* element data */
135
136         for (size_t i = 0; i < n; i++)
137         {
138                 /* need to cast to (char *) temporarily for byte level acuracy */
139                 ret[i] = (char **)((char *)ret +             /* base address */
140                                    n * sizeof (void **) +    /* skip 1. dim header */
141                                    i * m * sizeof (void *)); /* skip to 2. dim header */
142                 for (size_t j = 0; j < m; j++)
143                         ret[i][j] = (char *)ret +              /* base address */
144                                     n * sizeof (void **) +     /* skip 1. dim header */
145                                     n * m * sizeof (void *) +  /* skip 2. dim header */
146                                     i * m * o * elementSize +  /* skip to 2. dim part */
147                                         j * o * elementSize;   /* skip to 3. dim row data */
148         }
149         return (void ***)ret;
150 }
151
152
153 /**
154  * Allocate and initialize memory. Checks the return value, aborts if no more
155  * memory is available.  Don't use #GNUNET_xmemdup_() directly. Use the
156  * GNUNET_memdup() macro.
157  *
158  * @param buf buffer to initialize from (must contain size bytes)
159  * @param size number of bytes to allocate
160  * @param filename where is this call being made (for debugging)
161  * @param linenumber line where this call is being made (for debugging)
162  * @return allocated memory, never NULL
163  */
164 void *
165 GNUNET_xmemdup_ (const void *buf,
166                  size_t size,
167                  const char *filename,
168                  int linenumber)
169 {
170   void *ret;
171
172   /* As a security precaution, we generally do not allow very large
173    * allocations here */
174   GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber);
175 #ifdef W32_MEM_LIMIT
176   size += sizeof (size_t);
177   if (mem_used + size > W32_MEM_LIMIT)
178     return NULL;
179 #endif
180   GNUNET_assert_at (size < INT_MAX, filename, linenumber);
181   ret = malloc (size);
182   if (ret == NULL)
183   {
184     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc");
185     GNUNET_assert (0);
186   }
187 #ifdef W32_MEM_LIMIT
188   *((size_t *) ret) = size;
189   ret = &((size_t *) ret)[1];
190   mem_used += size;
191 #endif
192   GNUNET_memcpy (ret, buf, size);
193   return ret;
194 }
195
196
197 /**
198  * Wrapper around malloc(). Allocates size bytes of memory.
199  * The memory will be zero'ed out.
200  *
201  * @param size the number of bytes to allocate
202  * @param filename where in the code was the call to GNUNET_malloc_unchecked()
203  * @param linenumber where in the code was the call to GNUNET_malloc_unchecked()
204  * @return pointer to size bytes of memory, NULL if we do not have enough memory
205  */
206 void *
207 GNUNET_xmalloc_unchecked_ (size_t size,
208                            const char *filename,
209                            int linenumber)
210 {
211   void *result;
212
213 #ifdef W32_MEM_LIMIT
214   size += sizeof (size_t);
215   if (mem_used + size > W32_MEM_LIMIT)
216     return NULL;
217 #endif
218
219   result = malloc (size);
220   if (NULL == result)
221     return NULL;
222   memset (result, 0, size);
223
224 #ifdef W32_MEM_LIMIT
225   *((size_t *) result) = size;
226   result = &((size_t *) result)[1];
227   mem_used += size;
228 #endif
229
230   return result;
231 }
232
233
234 /**
235  * Reallocate memory. Checks the return value, aborts if no more
236  * memory is available.
237  *
238  * @param ptr the pointer to reallocate
239  * @param n how many bytes of memory to allocate
240  * @param filename where in the code was the call to GNUNET_realloc()
241  * @param linenumber where in the code was the call to GNUNET_realloc()
242  * @return pointer to size bytes of memory
243  */
244 void *
245 GNUNET_xrealloc_ (void *ptr,
246                   size_t n,
247                   const char *filename,
248                   int linenumber)
249 {
250 #ifdef W32_MEM_LIMIT
251   n += sizeof (size_t);
252   ptr = &((size_t *) ptr)[-1];
253   mem_used = mem_used - *((size_t *) ptr) + n;
254 #endif
255   ptr = realloc (ptr, n);
256   if ((NULL == ptr) && (n > 0))
257   {
258     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "realloc");
259     GNUNET_assert (0);
260   }
261 #ifdef W32_MEM_LIMIT
262   ptr = &((size_t *) ptr)[1];
263 #endif
264   return ptr;
265 }
266
267
268 # if __BYTE_ORDER == __LITTLE_ENDIAN
269 #define BAADFOOD_STR "\x0D\xF0\xAD\xBA"
270 #endif
271 # if __BYTE_ORDER == __BIG_ENDIAN
272 #define BAADFOOD_STR "\xBA\xAD\xF0\x0D"
273 #endif
274
275 #if WINDOWS
276 #define M_SIZE(p) _msize (p)
277 #endif
278 #if HAVE_MALLOC_NP_H
279 #include <malloc_np.h>
280 #endif
281 #if HAVE_MALLOC_USABLE_SIZE
282 #define M_SIZE(p) malloc_usable_size (p)
283 #elif HAVE_MALLOC_SIZE
284 #define M_SIZE(p) malloc_size (p)
285 #endif
286
287 /**
288  * Free memory. Merely a wrapper for the case that we
289  * want to keep track of allocations.
290  *
291  * @param ptr the pointer to free
292  * @param filename where in the code was the call to GNUNET_free
293  * @param linenumber where in the code was the call to GNUNET_free
294  */
295 void
296 GNUNET_xfree_ (void *ptr,
297                const char *filename,
298                int linenumber)
299 {
300   GNUNET_assert_at (NULL != ptr,
301                     filename,
302                     linenumber);
303 #ifdef W32_MEM_LIMIT
304   ptr = &((size_t *) ptr)[-1];
305   mem_used -= *((size_t *) ptr);
306 #endif
307 #if defined(M_SIZE)
308 #if ENABLE_POISONING
309   {
310     const uint64_t baadfood = GNUNET_ntohll (0xBAADF00DBAADF00DLL);
311     uint64_t *base = ptr;
312     size_t s = M_SIZE (ptr);
313     size_t i;
314
315     for (i=0;i<s/8;i++)
316       base[i] = baadfood;
317     GNUNET_memcpy (&base[s/8], &baadfood, s % 8);
318   }
319 #endif
320 #endif
321   free (ptr);
322 }
323
324
325 /**
326  * Dup a string (same semantics as strdup).
327  *
328  * @param str the string to dup
329  * @param filename where in the code was the call to GNUNET_strdup()
330  * @param linenumber where in the code was the call to GNUNET_strdup()
331  * @return `strdup(@a str)`
332  */
333 char *
334 GNUNET_xstrdup_ (const char *str,
335                  const char *filename,
336                  int linenumber)
337 {
338   char *res;
339   size_t slen;
340
341   GNUNET_assert_at (str != NULL,
342                     filename,
343                     linenumber);
344   slen = strlen (str) + 1;
345   res = GNUNET_xmalloc_ (slen,
346                          filename,
347                          linenumber);
348   GNUNET_memcpy (res,
349           str,
350           slen);
351   return res;
352 }
353
354
355 #if ! HAVE_STRNLEN
356 static size_t
357 strnlen (const char *s,
358          size_t n)
359 {
360   const char *e;
361
362   e = memchr (s, '\0', n);
363   if (NULL == e)
364     return n;
365   return e - s;
366 }
367 #endif
368
369
370 /**
371  * Dup partially a string (same semantics as strndup).
372  *
373  * @param str the string to dup
374  * @param len the length of the string to dup
375  * @param filename where in the code was the call to GNUNET_strndup()
376  * @param linenumber where in the code was the call to GNUNET_strndup()
377  * @return `strndup(@a str,@a len)`
378  */
379 char *
380 GNUNET_xstrndup_ (const char *str,
381                   size_t len,
382                   const char *filename,
383                   int linenumber)
384 {
385   char *res;
386
387   if (0 == len)
388     return GNUNET_strdup ("");
389   GNUNET_assert_at (NULL != str,
390                     filename,
391                     linenumber);
392   len = strnlen (str,
393                  len);
394   res = GNUNET_xmalloc_ (len + 1,
395                          filename,
396                          linenumber);
397   GNUNET_memcpy (res, str, len);
398   /* res[len] = '\0'; 'malloc' zeros out anyway */
399   return res;
400 }
401
402
403 /**
404  * Grow an array.  Grows old by (*oldCount-newCount)*elementSize bytes
405  * and sets *oldCount to newCount.
406  *
407  * @param old address of the pointer to the array
408  *        *old may be NULL
409  * @param elementSize the size of the elements of the array
410  * @param oldCount address of the number of elements in the *old array
411  * @param newCount number of elements in the new array, may be 0
412  * @param filename where in the code was the call to GNUNET_array_grow()
413  * @param linenumber where in the code was the call to GNUNET_array_grow()
414  */
415 void
416 GNUNET_xgrow_ (void **old,
417                size_t elementSize,
418                unsigned int *oldCount,
419          unsigned int newCount,
420                const char *filename,
421                int linenumber)
422 {
423   void *tmp;
424   size_t size;
425
426   GNUNET_assert_at (INT_MAX / elementSize > newCount, filename, linenumber);
427   size = newCount * elementSize;
428   if (0 == size)
429   {
430     tmp = NULL;
431   }
432   else
433   {
434     tmp = GNUNET_xmalloc_ (size, filename, linenumber);
435     if (NULL != *old)
436     {
437       GNUNET_memcpy (tmp, *old, elementSize * GNUNET_MIN(*oldCount, newCount));
438     }
439   }
440
441   if (NULL != *old)
442   {
443     GNUNET_xfree_ (*old, filename, linenumber);
444   }
445   *old = tmp;
446   *oldCount = newCount;
447 }
448
449
450 /**
451  * Like asprintf(), just portable.
452  *
453  * @param buf set to a buffer of sufficient size (allocated, caller must free)
454  * @param format format string (see printf(), fprintf(), etc.)
455  * @param ... data for format string
456  * @return number of bytes in `*@a buf`, excluding 0-termination
457  */
458 int
459 GNUNET_asprintf (char **buf,
460                  const char *format,
461                  ...)
462 {
463   int ret;
464   va_list args;
465
466   va_start (args, format);
467   ret = VSNPRINTF (NULL, 0, format, args);
468   va_end (args);
469   *buf = GNUNET_malloc (ret + 1);
470   va_start (args, format);
471   ret = VSPRINTF (*buf, format, args);
472   va_end (args);
473   return ret;
474 }
475
476
477 /**
478  * Like snprintf(), just aborts if the buffer is of insufficient size.
479  *
480  * @param buf pointer to buffer that is written to
481  * @param size number of bytes in buf
482  * @param format format strings
483  * @param ... data for format string
484  * @return number of bytes written to buf or negative value on error
485  */
486 int
487 GNUNET_snprintf (char *buf,
488                  size_t size,
489                  const char *format, ...)
490 {
491   int ret;
492   va_list args;
493
494   va_start (args, format);
495   ret = VSNPRINTF (buf, size, format, args);
496   va_end (args);
497   GNUNET_assert (ret < size);
498   return ret;
499 }
500
501
502 /**
503  * Create a copy of the given message.
504  *
505  * @param msg message to copy
506  * @return duplicate of the message
507  */
508 struct GNUNET_MessageHeader *
509 GNUNET_copy_message (const struct GNUNET_MessageHeader *msg)
510 {
511   struct GNUNET_MessageHeader *ret;
512   uint16_t msize;
513
514   msize = ntohs (msg->size);
515   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
516   ret = GNUNET_malloc (msize);
517   GNUNET_memcpy (ret, msg, msize);
518   return ret;
519 }
520
521
522 /* end of common_allocation.c */