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